Compact String Set with smart pointers - c++

The project was to make our own set class that we went over, but to use smart pointers. I got all my functions to work without smart pointer, but now that I tried to use them I'm getting issues with creating a new node.
#include "cs19_compact_string_set.h"
#include <memory>
#include <queue>
#include <string>
#include <utility>
#include <vector>
#include <string>
namespace cs19 {
CompactStringSet::CompactStringSet() :root_{0}, num_strings_{0} {}
bool CompactStringSet::insert(const std::string& value) {
if (this->find(value)) return true;
auto cur = this->root_;
for (auto character : value) {
auto search = this->find_next(cur, character);
if (search) {
cur = search;
} else {
auto new_node = std::shared_ptr<CompactStringSet::Node>(character);
if (cur->child) {
cur = cur->child;
while (cur->sibling)
cur = cur->sibling;
cur->sibling = new_node;
} else {
cur->child = new_node;
}
cur = new_node;
}
}
if (!cur->terminal) {
++this->num_strings_;
cur->terminal = true;
}
return false;
}
std::shared_ptr<CompactStringSet::Node> CompactStringSet::find_next(const
std::shared_ptr<CompactStringSet::Node> base, char to_find) const {
if (base->child) {
if (base->child->letter == to_find)
return base->child;
auto sibling = base->child->sibling;
while (sibling) {
if (sibling->letter == to_find)
return sibling;
sibling = sibling->sibling;
}
}
return nullptr; // No match found
}
} // namespace cs19
In the file where the functions are being implemented I keep getting errors for trying to make a new shared_ptr with the value character. I've tried to change it in a few different ways. but can't solve the issue. The error keeps reading error: no matching function for call to ‘std::shared_ptrcs19::CompactStringSet::Node::shared_ptr(char&)’.
#ifndef CS19_COMPACT_STRING_SET_H_
#define CS19_COMPACT_STRING_SET_H_
#include <memory>
#include <queue>
#include <string>
#include <utility>
#include <vector>
#include <string>
namespace cs19 {
class CompactStringSet {
struct Node {
char letter; // each node stores a letter
bool terminal = false; // ... and is potentially the end of a string in the set
std::shared_ptr<Node> sibling = nullptr;
std::shared_ptr<Node> child = nullptr;
};
public:
CompactStringSet();
bool insert(const std::string& value);
bool find(const std::string& value) const;
bool end() const {
return false;
}
std::size_t size() const {
return this->num_strings_;
}
private:
std::shared_ptr<Node> root_{0};
std::size_t num_strings_ = 0;
std::shared_ptr<Node> find_next(const std::shared_ptr<Node> base, char to_find) const;};
} // namespace cs19
#endif

You are trying to create a new instance of CompactStringSet by giving it a character as a parameter in the constructor
auto new_node = std::shared_ptr<CompactStringSet::Node>(character);
But your structure doesn't take any parameters and doesn't have any constructor, it's what the error says.
So you should propably replace it by :
auto new_node = std::make_shared<CompactStringSet::Node>();
new_node->letter = character;
You should also use make_shared instead of shared_ptr when you want to create a new shared_ptr

You code fails because you are trying to invoke a non existent function here
auto new_node = std::shared_ptr<CompactStringSet::Node>(character);
Seems like you somehow expect this to create a new node, assign the character to its 'letter' member and create a shared_ptr pointing at the new node. This is wishful thinking, no such function exisits - hence
no matching function for call to ‘std::shared_ptrcs19::CompactStringSet::Node::shared_ptr(char&)’.
You need (since you have no constructor for 'node' that accepts a character argument)
auto new_nodew = std::make_shared<CompactStringSet::Node>();
new_node->letter = character;

Related

Question related to container construct and release

I have written a customized hash map, whose value contains an std::vector. And it caused core dump in real environment. There is a simplified example below. There are three questions:
Why vector size doesn't change to zero when I called the destruct function ~Value()? Does this program really release the memory allocated by vector before when I call the destruct function? And when I gdb attaches to this program, it's __M_start and __M_finish pointer still point to the same address.
Add1 and Add2 both have memory problems. Add1 won't call the construct function of vector, when I push_back int* to the vector of Value which has been erase before, it might be added to an illegal address. When I want to use the Add2 function to call the copy construct function, it might cause segment fault. Why it is still not working with Add2?
How should I change my program if I still want to use my customized map instead of std::map?
#include <iostream>
#include <functional>
#include <cstdlib>
#include <stdio.h>
#include <memory>
#include <vector>
#include <algorithm>
#include<iterator>
#include <map>
#include <iterator>
#include <limits>
#include <set>
using namespace std;
class Value
{
public:
// Value()
// {
// }
// Value(const Value &obj): stArr(obj.stArr)
// {
// cout<<"Call copy construct"<<endl;
// }
vector<int*> stArr;
};
class CustomMap
{
public:
// normal way
void Add1(int key, const Value& val)
{
stArrVal[key] = val;
}
// placement new
void Add2(int key, const Value& val)
{
new (&stArrVal[key]) Value(val);
// stArrVal[key] = val;
}
// void Add2(int key, const Value& val)
// {
// new (&stArrVal[key]) Value(val);
// }
void Erase(int key)
{
stArrVal[key].~Value();
// stArrVal[key].stArr.clear();
cout<<stArrVal[key].stArr.size()<<endl;
}
void Search(int key, Value *&pstVal)
{
pstVal = &stArrVal[key];
}
Value stArrVal[100];
};
void PrintValAddress(Value *pVal)
{
for (const auto & val : pVal->stArr)
{
cout<<&val<<", ";
}
cout<<endl;
}
int main()
{
vector<int> arr;
arr.push_back(1);
arr.push_back(3);
std::map<int, Value> stlMap;
CustomMap customMap;
Value* value = new Value();
Value* value2 = new Value();
int a = 1;
int b = 2;
int c = 3;
value->stArr.push_back(&a);
value->stArr.push_back(&b);
value->stArr.push_back(&c);
value2->stArr.push_back(&a);
value2->stArr.push_back(&b);
value2->stArr.push_back(&c);
// value2->stArr.push_back(&d);
stlMap.insert(pair<int, Value>(1, *value));
Value &stlV = stlMap[1];
Value *pstCusV = NULL;
customMap.Add1(1, *value);
customMap.Add2(2, *value);
customMap.Search(1, pstCusV);
PrintValAddress(pstCusV);
customMap.Search(2, pstCusV);
PrintValAddress(pstCusV);
// Release
customMap.Erase(1);
customMap.Erase(2);
// this line will cause segment fault.
// int* arr2 = new int[1024*1024];
customMap.Search(2, pstCusV);
// 1. still size 3
PrintValAddress(pstCusV);
// int* arr1 = new int[10];
customMap.Add1(1, *value2);
customMap.Add2(2, *value2);
customMap.Search(1, pstCusV);
PrintValAddress(pstCusV);
customMap.Search(2, pstCusV);
PrintValAddress(pstCusV);
return 0;
}
Output:
0xa14090, 0xa14098, 0xa140a0,
0xa14160, 0xa14168, 0xa14170,
3
3
0xa14160, 0xa14168, 0xa14170,
0xa14090, 0xa14098, 0xa140a0,
0xa14160, 0xa14168, 0xa14170,
Thanks a lot!

Why does creating an instance of a friend class cause "undefined reference to" error?

I'm having trouble wrapping my head around why this code is not compiling. I am implementing a stack as a doubly linked list. I cannot get my AddToHead() to work. More specifically, the program wont compile if I try to dynamically create a CharNode object. I thought by having #include "charlist.h" would give the program access to the CharNode class, since it resides in charlist.h
I compile with: g++ -ansi -pedantic -Wall charlist.cxx -o clist
This is the error I get:
/tmp/ccHzaOmz.o: In function `CharList::AddToHead(char)':
charlist.cxx:(.text+0xe9): undefined reference to `CharNode::CharNode(char, CharNode*, CharNode*)'
collect2: error: ld returned 1 exit status
I know that undefined reference means that the CharNode resources can't be found by the linker. I just don't know why it is happening here.
Here is charlist.h
#ifndef __CharList__
#define __CharList__
#include <iostream>
#include <string>
using namespace std;
class CharList;
//CharNode class is clearly here in charlist.h
class CharNode
{
private:
char value;
CharNode* prev;
CharNode* next;
public:
CharNode(char value, CharNode* prev = NULL, CharNode* next = NULL);
friend class CharList;
};
class CharList
{
private:
CharNode* h;
CharNode* t;
public:
CharList();
~CharList();
bool IsEmpty() const;
char GetHead() const; //FUNCTION CAUSING ERROR
char GetTail() const;
void AddToHead(char v);
void AddToTail(char v);
};
#endif //__CharList__
Here is charlist.cxx
#include <iostream>
#include <string>
#include <sstream>
#include <cassert>
#include <stdlib.h>
#include "charlist.h"
using namespace std;
CharList::CharList()
{
h = t = NULL;
}
bool CharList::IsEmpty() const
{
return (h == NULL);
}
//All other member functions excluded for relevancy
void CharList::AddToHead(char v){
CharNode* newHead;
newHead = new CharNode(v); //Why cant I do this? Error Line.
newHead->prev = NULL;
newHead->next = h;
if (IsEmpty()){
t = newHead;
h = newHead;
} else {
h->prev = newHead;
h = newHead;
}
}
Below, you have a declaration of a constructor. This is a promise that you will define a constructor, somewhere.
CharNode(char value, CharNode* prev = NULL, CharNode* next = NULL);
Change it to also include the definition, and you will not get that undefined error.
CharNode(char value, CharNode* prev = NULL, CharNode* next = NULL)
: value(value)
, prev(prev)
, next(next)
{
}
Because you have not defined CharNode::CharNode() anywhere yet.
Fill in the following in your charlist.cxx and it should build and link:
CharNode::CharNode(char value, CharNode* prev = NULL, CharNode* next = NULL)
{
// Your code here...
}

how to change from a list of strings to a list of pointers to strings

I am trying to get this to return a string, but i am having trouble getting it working. The goal is to have a doubly-linked list that points to strings. I am not allowed to have it contain the string, it must point to it instead. Currently i am having trouble getting my program to use it. For example, it always seems to return what the command was, and its confusing me and hard to explain.
#ifndef DOUBLY_LINKED_LIST_H
#define DOUBLY_LINKED_LIST_H
#include <iostream>
#include <string>
//#include "Playlist.h"
using namespace std;
class DoublyLinkedList
{
public:
DoublyLinkedList();
~DoublyLinkedList();
bool empty();
void append(string& s);
void insertBefore(string& s);
void insertAfter(string& s);
void remove(string& s);
void begin();
void end();
bool next();
bool prev();
bool find(string& s);
const string& getData();
private:
class Node
{
public:
Node (string *data, Node *next, Node *prev)
{m_data = data; m_next = next; m_prev = prev;}
string *m_data;
Node * m_next;
Node * m_prev;
};
Node *m_head;
Node *m_tail;
Node *m_current;
};
#endif // DOUBLYLINKEDLIST_H_INCLUDED
.cpp file>>>>
const string& DoublyLinkedList::getData()
{
string *m_tmp;
m_tmp = m_current->m_data;
cout << m_current->m_data << endl;
//cout << "returning: " << m_current->m_data << endl;
// return m_current->m_data;
return *m_tmp;
}
void DoublyLinkedList::append(string &s)
{
if (!m_head)
{
m_head = new Node(&s, NULL, NULL);
m_tail = m_head;
m_current = m_head;
}
else
{
m_tail->m_next = new Node (&s, NULL, m_tail);
m_tail = m_tail->m_next;
m_current = m_tail;
}
}
Consider the following example:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void store_value(vector<string*>& vec, string& str)
{
vec.push_back(&str);
}
void create_and_store_value(vector<string*>& vec)
{
string str("This string is temporary");
store_value(vec, str);
}
int main(int argc, char** argv)
{
vector<string*> pointers;
create_and_store_value(pointers);
cout << *pointers.back() << endl;
string myPersistingString("Yay");
store_value(pointers, myPersistingString);
cout << *pointers.back() << endl;
return 0;
}
This example contains two function, a function store_value which behaves similar to your append function (except, for the purposes of this example working on a std::vector) and a second function showing the possible danger of taking the address of a reference (this is one of the possible hazards that I believe Manu343726 and Mats Petersson are preluding too).
The reason this is dangerous is because the string declared inside create_and_store_value does not persist after the completion of the function. This means that we are left with a pointer to memory which is probably not what we expect. On the other hand, creating a string inside the main function is fine, since the string there persists until the end of the program.
For us to help you further, I would suggest editing your question to give us an example of how you are calling your function. I would suggest pasting a minimal striped down version of your code including an example of how you are calling append, something like:
#include <blah>
class DoubleLinkedList
{
DoubleLinkedList(void)
{
// Include these inline to make copying and pasting simpler.
}
~DoubleLinkedList(void)
{
...
}
append(...) { ... }
getData(...) { ... }
};
int main(int argc, char** argv)
{
DoubleLinkedList dll;
// Show us how you are using this list
return 0;
}
In the above, replace the comments and dots with the relevant code.

VC++ debug assertion failed on program exit

I'm trying to create a linked list class template (Yes, I know there's one in the c++ library but I wanted to create my own for fun). I've traced through the code and all seems well until the program exits.
Here's the used code:
list.h:
#ifndef LIST_H
#define LIST_H
#include "misc.h"
template <typename T> class CList {
private:
class CNode {
friend CList;
private: T data;
CNode* next;
public: CNode() : next(NULL) {}
~CNode() { delete [] next; }
};
private: int length;
CNode* first;
public:
CList() : length(0), first(NULL) {}
CList(int i_length) : first(NULL) {
int i;
CNode* cur = NULL;
CNode* prev = NULL;
if (i_length < 0) length = 0;
else length = i_length;
for (i=0;i<length;i++) {
// allocate new CNode on heap
cur = new2<CNode>();
// attach preceding CNode pointer
if (prev) prev->next = cur;
else first = cur;
prev = cur;
}
}
~CList() { delete first; }
};
misc.h
#ifndef MISC_H
#define MISC_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
inline void terminate( const char* message, int code ) {
printf("\n\n%s\n\n",message);
system("pause");
exit(code);
};
template <typename T> inline T* new2() {
T* ret = new T;
if (!ret) terminate("Insufficient Memory",-2);
return ret;
}
template <typename T> inline T* new2(int num) {
if (num <= 0) terminate("Invalid Argument",-1);
T* ret = new T[num];
if(!ret) terminate("Insufficient Memory",-2);
return ret;
}
#endif
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include "../Misc/misc.h"
#include "../Misc/list.h"
int main(int argc, char* argv[]) {
//CList<int> m;
CList<int> n(5);
system("pause");
return 0;
}
Here is what the variable "n" looks like at the breakpoint just before "return 0;".
http://s20.beta.photobucket.com/user/marshallbs/media/Untitled_zps52497d5d.png.html
Here's the context in which the error occurs. Unfortunately at this point I can no longer view the variable "n" on the watch list.
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
There is no error when I use the default constructor for my list. I don't understand what's going on as the memory release process should stop when it reaches the fifth CNode object which has a null "next" pointer. It acts as though it's trying to releasing an invalid non-null pointer but I don't see how this can happen.
I built and ran (from the debugger) the code as-is and got no assertion failures. In fact, there is no memory deallocation at all because CList doesn't have a destructor (didn't you post the complete code?).
One problem is that you allocate next using new and free it using delete[]. This is undefined behaviour.
Allocation:
cur = new2<CNode>(); // new2 uses `new' and not `new[]'
Deallocation:
~CNode() { delete [] next; }
Replace the latter with delete next;.

Pointing to an object of the same type

I feel this question may be a bit trivial, but I simply cannot wrap my head around it. I currently have a class, Node, which is trying to point to what node occurs before the current node using the pointer prevNode. However I seem unable to access any variables within prevNode.
When running Main.cpp from the following code, it prints the result '15340756'. Where am I going wrong? Appologies as Im still a bit new to C++.
Node.h
#include "stdafx.h"
class Node
{
public:
Node();
void setPrevNode(Node n);
Node getPrevNode();
int i;
private:
Node *prevNode;
};
Node.cpp
#include "stdafx.h"
#include "Node.h"
Node::Node(){
i = 0;
}
void Node::setPrevNode(Node n){
prevNode = &n;
}
Node Node::getPrevNode(){
return *prevNode;
}
Main.cpp
#include "stdafx.h"
#include "Node.h"
int _tmain(int argc, _TCHAR* argv[])
{
Node nodes[] = {Node(), Node()};
nodes[0].i = 1;
nodes[1].setPrevNode(nodes[0]);
printf("%i", nodes[1].getPrevNode().i);
while(true){
}
return 0;
}
void setPrevNode(Node n);
Here setPrevNode is declared to take a copy of the node passed as an argument, and point to such node. After the function returns, the pointed to node no longer exist and what you get is undefined behavior.
What you want is to take the Node either as a reference or a pointer instead:
void setPrevNode(Node& n)
{
prevNode = &n;
}
void setPrevNode(Node* n)
{
prevNode = n;
}
On the same line, getPrevNode is defined to return a copy of the previous node. You most certainly want to return a reference here instead, although you can also return a pointer:
Node& getPrevNode()
{
return *prevNode;
}
Node* getPrevNode()
{
return prevNode;
}