I would like to save (serialize) an MFC tree control in a dialog and recall it to populate the tree when the dialog is initialized. I thought the way to approach that task would be to first code a program that creates a (preferably) vector representation of the tree, stores it in a text file, and then recreates the tree representation by deserializing from the saved file. I would also prefer to save the nodes as CStrings because that’s how I’m used to saving and reading text from files. However, not only can I not get to first base on this, I can’t even pick up the bat. The following minimal code to create a single node using std::string runs ok.
#include <string>
#include <vector>
// A node of N-ary tree
struct Node {
std::string key;
std::vector<Node*> child; // An array of pointers for children
};
// A utility function to create a new N-ary tree node
Node* newNode(std::string key)
{
Node* temp = new Node;
temp->key = key;
return temp;
}
// A utility function to create a tree
Node* createTree()
{
Node* root = newNode( "Root" );
return root;
}
int main()
{
Node* root = createTree();
return 0;
}
But if I change it to use CString instead,
#include <afx.h>
#include <tchar.h>
#include <vector>
struct Node {
CString key;
std::vector<Node*> child; // An array of pointers for children
};
Node* newNode(CString key)
{
Node* temp = new Node;
temp->key = key;
return temp;
}
Node* createTree()
{
Node* root = newNode( _T("Root") );
return root;
}
…when the program exits it reports a memory leak. Could someone please explain why, and what if anything I can do to correct it?
As the previous answer and comments noted, someone has to free all allocated memory.
When you use new, the responsibility is on you.
However, C++ provides smart pointers that can manage memory allocation and freeing for you; please see https://en.cppreference.com/w/cpp/memory/unique_ptr.
Your sample code will look like this:
#include <atlstr.h>
#include <tchar.h>
#include <vector>
#include <memory>
struct Node {
CString key;
std::vector<std::unique_ptr<Node>> child;
};
std::unique_ptr<Node> newNode(CString key)
{
std::unique_ptr<Node> temp = std::make_unique<Node>();
temp->key = key;
return temp;
}
std::unique_ptr<Node> createTree()
{
std::unique_ptr<Node> root = newNode(_T("Root"));
root->child.push_back(newNode(_T("Child")));
return root;
}
APPENDED per question in the comment:
CString encode(std::unique_ptr<Node>& root)
{
if (root == nullptr)
return _T("");
{
CString sRep = root->key;
for (auto& temp : root->child)
sRep += encode(temp);
return sRep += _T("|");
}
}
It appears you have a memory leak in your original iteration as well (without using CString). You allocate memory on the heap for a new Node in newNode(std::string), but you never call delete on that pointer anywhere.
Simply delete root; somewhere before main() exits to fix this first memory leak.
Next, you'll find that once you populate the vector<Node*> child with pointers, those will need to be deleted somehow as well. I suggest adding a destructor to your struct Node that iterates through vector and explicitly calls delete on each pointer in there.
A note on CString
A quick search about how CString works[1] (because I've never dealt with it before) indicates that when you make a copy of a CString (such as by using the copy assignment operator), a new object isn't created, but a reference counter is incremented in the original CString object. The object is only destroyed once that reference counter reaches zero.
Since you're never calling delete on your Node pointer, the CString object in the Node object is never deleted, and this reference number is never decreased. Calling delete should fix the problem, but please report back whether or not it does.
Related
I am currently working on a large data tree. I need to navigate the tree, return a subnode and change its value.
class Node {
short value;
std::vector<Node> children;
Node walk(int step) {
return children[step];
}
}
Will the return of the Walk function create a copy of the child Node or do I have to return a pointer? How should I Link the Nodes?
also another question:
what's the difference between these two and which should I use to create new nodes:
Node newNode;
// or
Node newNode = *new Node();
Edit
I tried std::vector<Node*> children; but this lead to memory leaks when deleting. Would Node& walk(int step) work too without using pointers?
To prevent memory leaks and keep your code clean, you can use shared pointers. Return weak pointer from walk function. We must return the weak pointer so as not to make the client the owner of a particular node.
#include<memory>
#include<vector>
class Node;
using NodePtr = std::shared_ptr<Node>;
using NodeWPtr = std::weak_ptr<Node>;
class Node {
short value;
std::vector<NodePtr> children;
NodeWPtr walk(int step) {
//Your Algorithm.
return children[step];
}
};
Node newNode = *new Node(); creates a Node on the heap and then copies it to a node on the stack. This however, has memory leak and it does not do anything significantly different than just creating a node directly on the stack.
Node newNode; creates Node object on the stack. I would suggest you use this as it directly describes your intent.
Some people have suggested the use of std::unique_ptr instead of std::shared_ptr because std::shared_ptr has a large overhead. However, if we do use std::unique_ptr, we would have to return an std::observer_ptr from the walk function which is not fully implemented in the latest c++ compilers as far as I know.
EDIT
The following 2 class designs are noteworthy of consideration according to the discussions in the comments.
//Without storing any pointers in the vector
class Node {
short value;
std::vector<Node> children;
Node* walk(int step) {
//Your Algorithm.
return &children[step];
}
};
or
//Using unique_ptr
class Node;
using NodePtr = std::unique_ptr<Node>;
class Node {
short value;
std::vector<NodePtr> children;
Node* walk(int step) {
//Your Algorithm.
return children[step].get();
}
};
How to deal with memory leaking with template classes in C++?
In this code I defined 4 template classes:
class node and class linked_list make up a doubly linked list
class item and class bag just make up another doubly linked list
These template classes are designed to deal with objects of various classes.
In the main function, I first created a linked_list<string> and a bag<int> and everything is fine.
But when I try to make a bag<linked_list<string>>, problems arise.
I tried to trace back to see what happened, and I saw that in the function push_back in class bag, a destructor of linked_list has been called that erased all the data in the input v. I don't know why that happens.
Note that I overwrote the destructors for all classes and called className.~className() in the main function to prevent memory leaking.
And it does work to prevent memory leaking from ls_1 and bag_1.
I don't know which part of my code is wrong. Can somebody help me?
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
//node and linked_list class make up a doubly linked list
template<class T> class node {
public:
T value;
node<T> * next;
node<T> * previous;
node<T>() { next = nullptr; previous = nullptr; }
node<T>(T v) { value = v; next = nullptr; previous = nullptr; }
~node<T>() { delete next; }
};
template<class T> class linked_list { //doubly linked list
public:
node<T> * head;
node<T> * tail;
linked_list<T>() { head = nullptr; tail = nullptr; }
~linked_list<T>() { delete head; }
void push_front(T v) { //insert an item to the front
node<T> * p = new node<T>(v);
p->next = head;
head = p;
if (tail == nullptr) {
tail = p;
}
}
};
//item and bag class just make up another doubly linked list
template<class X> class item {
public:
X value;
item<X> *next;
item<X> *previous;
item<X>(X v) { value = v; next = nullptr; previous = nullptr; }
~item<X>() { delete next; }
};
template<class X> class bag { //just another doubly linked list
public:
item<X> *last;
item<X> *first;
int num_items;
int size() { return num_items; }
bag() { last = nullptr; first = nullptr; num_items = 0; }
~bag() { delete first; }
void push_back(X v) { //insert an item to the back
item<X> * p = new item<X>(v);
if (num_items == 0) {
last = first = p;
}
else {
last->next = p;
p->previous = last;
last = p;
}
num_items++;
last->next = nullptr;
}
};
int main() {
//When using built-in classes (like strings) as input
//there's no problem at all
linked_list<string> ls_1;
ls_1.push_front("David");
ls_1.push_front("John");
bag<int> bag_1;
bag_1.push_back(1);
bag_1.push_back(2);
//Problems arise here when using user defined classes (linked_list) as input
//I traced back and found out that a destructor has been called
//that erases all the data in the input. Donno how that happens
bag<linked_list<string>> bag_string;
bag_string.push_back(ls_1);
//These lines are to prevent the memory leaking
//I overwrote destructors for linked_list and node class
//otherwise there's still memory leaking
ls_1.~linked_list();
bag_1.~bag();
bag_string.~bag();
_CrtDumpMemoryLeaks();
getchar();
getchar();
}
Implement node, linked_list, item, bag copy constructors and assignments or declare them as deleted. The default versions generated by the compiler do not do the deep copying and that leads to multiple deletes of same objects after they were copied.
Read the rule of three/five/zero for full details.
A bit off-topic, but making a list node delete its siblings is a classic gotcha: for a sufficiently long list it ends up calling ~node<T>() recursively until it exhausts the stack. And this is the reason node pointers cannot be smart-pointers.
A fix would be to have a default destructor for nodes and make the list destroy the nodes in a loop, rather than recursively.
You may also like to use the full list node as a head of the list that points to itself when empty. That removes that nullptr checking logic completely.
I tried to trace back to see what happened, and I saw that in the function push_back in class bag, a destructor of linked_list has been called that erased all the data in the input v
Yes, this happens because your bag::push_back() takes its argument by value. This means it creates a copy of the ls_1 you created in main. You have not specified how to "copy" a list, so the compiler generated this function (a copy constructor) automatically. It can do that because your linked_list only contains two pointers, so the compiler assumes (because you have not told it otherwise) that copying the pointers over is all that is necessary to generate a copy of a linked_list. Unfortunately, that is not correct.
You now have two lists that manage the same contents: The original ls_1 in main() and the function argument v in push_back() - they both contain the same pointers.
Then the same thing happens again in your item constructor: You make a local copy of the list that holds the same pointers as the first two.
You now have several list objects pointing to the same data. Each one will try to destroy the data once it dies. This results in undefined behavior.
To correct this, you need to figure out how copying of a list should work. This is (in part) what the rule linked in the other comment is about: If the destructor of your class is not trivial (i.e. the compiler-generated version would not be sufficient, most likely because you need to release a resource like allocated memory), you should/must always care about how to handle your class being copied around. The various mechanisms that may invoke copy-like behavior (assignment, copy constructor, plus move versions in newer C++) need to be specified (or forbidden) by you.
Hello I am trying to use pointers and learning the basics on unique pointers in C++. Below is my code I have commented the line of code in main function. to debug the problem However, I am unable to do so. What am I missing ? Is my move() in the insertNode() incorrect ? The error I get is below the code :
#include<memory>
#include<iostream>
struct node{
int data;
std::unique_ptr<node> next;
};
void print(std::unique_ptr<node>head){
while (head)
std::cout << head->data<<std::endl;
}
std::unique_ptr<node> insertNode(std::unique_ptr<node>head, int value){
node newNode;
newNode.data = value;
//head is empty
if (!head){
return std::make_unique<node>(newNode);
}
else{
//head points to an existing list
newNode.next = move(head->next);
return std::make_unique<node>(newNode);
}
}
auto main() -> int
{
//std::unique_ptr<node>head;
//for (int i = 1; i < 10; i++){
// //head = insertNode(head, i);
//}
}
ERROR
std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
Aside from other small problems, the main issue is this line:
return std::make_unique<node>(newNode);
You are trying to construct a unique pointer to a new node, passing newNode to the copy constructor of node. However, the copy constructor of node is deleted, since node contains a non-copyable type (i.e. std::unique_ptr<node>).
You should pass a std::move(newNode) instead, but this is problematic since you create the node on the stack and it will be destroyed at the exit from the function.
Using a std::unique_ptr here is a bad idea in my opinion, since, for example, to print the list (or insert into the list), you need to std::move the head (so you lose it) and so on. I think you're much better off with a std::shared_ptr.
I was having the same problem and indeed using a shared_ptr works.
Using the smart pointer as an argument in the function copies the pointer (not the data it points to), and this causes the unique_ptr to reset and delete the data it was previously pointing at- hence we get that "attempting to reference a deleted function" error. If you use a shared_ptr this will simply increment the reference count and de-increment it once you are out of the scope of that function.
The comments in the answers above suggest that using a shared_ptr is baseless. These answers were written before the C++17 standard and it is my understanding that we should be using the most updated versions of the language, hence the shared_ptr is appropriate here.
I don't know why we have to expose node type to user in any case. Whole thingamajig of C++ is to write more code in order to write less code later, as one of my tutors said.
We would like to encapsulate everything and leave no head or tail (pun intended) of node to user. Very simplistic interface would look like:
struct list
{
private:
struct node {
int data;
std::unique_ptr<node> next;
node(int data) : data{data}, next{nullptr} {}
};
std::unique_ptr<node> head;
public:
list() : head{nullptr} {};
void push(int data);
int pop();
~list(); // do we need this?
};
The implementation does something what Ben Voigt mentioned:
void list::push(int data)
{
auto temp{std::make_unique<node>(data)};
if(head)
{
temp->next = std::move(head);
head = std::move(temp);
} else
{
head = std::move(temp);
}
}
int list::pop()
{
if(head == nullptr) {
return 0; /* Return some default. */
/* Or do unthinkable things to user. Throw things at him or throw exception. */
}
auto temp = std::move(head);
head = std::move(temp->next);
return temp->data;
}
We actually need a destructor which would NOT be recursive if list will be really large. Our stack may explode because node's destructor would call unique_ptr's destructor then would call managed node's destructor, which would call unique_ptr's destructor... ad nauseatum.
void list::clear() { while(head) head = std::move(head->next); }
list::~list() { clear(); }
After that default destructor would ping unique_ptr destructor only once for head, no recursive iterations.
If we want to iterate through list without popping node, we'd use get() within some method designed to address that task.
Node *head = list.head.get();
/* ... */
head = head->next.get();
get() return raw pointer without breaking management.
How about this example, in addition to the sample code, he also mentioned some principles:
when you need to "assign" -- use std::move and when you need to just traverse, use get()
This is the revised version.
It takes 3.5GB memory and the pop function doesn't free the memory... How can I use new and delete to get those memory back? Now I'm using STL. since new and delete only works for pointers?
queue<Graphnode> ss;
for(i=0;i<30000000;i++)
{
ss.push( *g.root);
}
printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
for(i=0;i<30000000;i++)
{
ss.pop();
}
printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
//delete &ss;
here is my node.h file. I think I need to malloc and free or New, delete pointers here?
#include <stdio.h>
#include <stdlib.h>
#include <tr1/array>
typedef struct point
{
std::tr1::array<int, 16> state;
int x;
}point;
typedef struct Graphnode
{
struct point pvalue;
int depth;
struct Graphnode *up;
struct Graphnode *down;
struct Graphnode *left;
struct Graphnode *right;
}Graphnode;
so after revise the code should look like this?
#include <stdio.h>
#include <stdlib.h>
#include <tr1/array>
typedef struct point
{
std::tr1::array<int, 16> state;
int x;
int depth;
}point;
typedef struct Graphnode
{
point *pvalue = (point *)malloc(sizeof(point));
Graphnode *up = (Graphnode*)malloc(sizeof(Graphnode));
Graphnode *down= (Graphnode*)malloc(sizeof(Graphnode));;
Graphnode *left= (Graphnode*)malloc(sizeof(Graphnode));;
Graphnode *right= (Graphnode*)malloc(sizeof(Graphnode));;
}Graphnode;
If you're using c++, you should use queue<T> from the standard library. Here is a reference: http://www.cplusplus.com/reference/stl/queue/.
For c++ code you should never write your own container classes unless it is absolutely necessary. The standard library provides many useful containers that cover most use cases. They are heavily used and tested and have been for many years.
Your queue can clean up after itself if and only if struct Graphnode is self-contained and does not contain pointers to allocated memory.
void emptyQueue(struct queue *q) {
queueElement *element, *nextElement;
element = q->head;
while(element) {
nextElement = element->next;
free(element);
element = nextElement;
}
initQueue(q);
}
Note that since initQueue does not malloc, its counterpart function, emptyQueue, should not free. This allows you to create queues on the stack if you need to.
If your struct Graphnode has pointers to allocated memory, then you will need to do this by hand, and not in emptyQueue. Your code will look something like:
struct Graphnode node;
while(!isEmpty(q)) {
node = front(q);
/* Delete the stuff in `node` here. */
dequeue(q);
}
Some comments on your C code...
In enqueue you have:
if (q->head == NULL) {
//first element
q->head = newElement;
q->tail = newElement;
} else {
//put it to the tail
q->tail->next= newElement;
q->tail = newElement;
}
Since you're doing q->tail = newElement; in both paths, move it out:
if (q->head == NULL) {
//first element
q->head = newElement;
} else {
//put it at the tail
q->tail->next= newElement;
}
q->tail = newElement;
Also, consistent indentation is a good habit to have. Your text editor should make this easy for you.
In dequeue:
if (q->head == NULL) {
//empty queue
return;
} else {
element = q->head;
q->head = q->head->next;
free(element);
}
The else isn't needed, since the first part always returns.
if (q->head == NULL) {
//empty queue
return;
}
element = q->head;
q->head = q->head->next;
free(element);
Finally, in ifEmpty:
return (q->head == NULL ? 1:0);
C represents true as nonzero and false as 0. The result of the == operator is guaranteed to be like this, so there's no point forcing true to be 1;
return q->head == NULL;
One final note: on some systems, the "memory used" read out by a program like top might not go down. This is because the system is keeping the pages of freed memory around for future use. It may release the physical memory, but the virtual memory addresses will be kept around as "available" for your program until termination.
Even an empty queue structure will still use memory. I am assuming you have defined queue as something like
struct queue
{
queueElement* head;
queueElement* tail;
};
So an empty queue will still require the memory to store the head and tail pointers even when they are both NULL.
How are you "measuring" the memory usage? Obviously sizeof is no good as it'll just be the constant size of the struct queue. So I assume you've got some other tool or code which is measuring it. But the code looks OK to me, and shuld be releasing the memory as you expect.
One bug you have is that the dequeue function never sets tail. But if head is NULL after setting it to head->next, then you also need to set tail to NULL. Don't think this would cause a memory leak, but definitely opens you up to a corruption or segfault if you enqueue after a dequeue empties the queue.
I'm attempting to craft my own basic singly linked list in C++ as a learning exercise, and I'm encountering some difficulty in the memory management department. As it stands I have...
A 'Node' class:
class Node
{
public:
char *value;
Node *next;
Node();
~Node();
};
Node::Node()
{
}
Node::~Node()
{
delete[] value;
}
And then my list (I've omitted certain method calls for brevity):
class LinkedList
{
private:
Node *head;
public:
LinkedList();
~LinkedList();
void Add(char **x);
};
LinkedList::LinkedList()
{
head = 0;
}
LinkedList::~LinkedList()
{
Node *temp;
Node *current = head;
while(current)
{
temp = current;
current = current->next;
delete temp;
}
}
void LinkedList::Add(char **x)
{
Node *nodeToAdd = new Node();
nodeToAdd->value = *x;
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
I'm attempting to use this code as follows (again I've omitted things for brevity):
int main()
{
LinkedList *list = new LinkedList();
char *alpha = "alpha";
char *beta = "beta";
char *charlie = "charlie";
char *delta = "delta";
char *echo = "echo";
list->Add(&alpha);
list->Add(&beta);
list->Add(&charlie);
list->Add(&delta);
list->Add(&echo);
delete list;
}
The last call in main to delete the list produces an error:
Debug Assertion Failed! Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
What am I doing wrong here?
The data pointed to by the various Node::value aren't dynamically allocated, so you shouldn't delete them. Applying the concept of "ownership", nodes should either make their own copies of data, which they own and can delete, or nodes don't own data, so they shouldn't be responsible for deleting it.
You can also implement multiple ownership using reference counting, like Objective-C does (see Objective-C Memory Management Rules for more info) but you have to be careful to avoid ownership cycles. You often find some type of reference counting in third-party smart pointers, such as Boost's smart_ptr library. Since you're doing this for the learning experience, it may make more sense to roll your own than use a library. Of course, you could also use a library for now, letting you focus on whatever you're trying to learn.
One day a student came to Moon and said: “I understand how to make a better garbage collector. We must keep a reference count of the pointers to each cons.”
Moon patiently told the student the following story:
“One day a student came to Moon and said: ‘I understand how to make a better garbage collector...
you are trying to release the memory which is not allocated on heap.
char *alpha = "alpha"; --- not allocated on heap
calling delete[]in Node destructor would lead to heap corruption.
Some points:
1) initialize pointers properly in the constructor:
Node::Node():value(NULL),next(NULL)
{
}
2) Take a ownership of value.
Allocate the memory on heap and copy
the contents
You shouldn't release a pointer use delete[]/delete if it's not created by new operator. There are some actions under the hood for the delete[] operation, like releasing/reclaiming marked memory from a managed pool. Since your pointer doesn't belong to these stuff, there will be a problem. IMHO, the underlying delete[] code is the _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) stuff.
The problem is that you're assuming that you can delete the data inside node, but you're passing in pointers to string literals instead, which you can't delete.
If you're assuming that the Node object controls the lifetime of the data inside it, your Node constructor or the Add function in LinkedList will have to make a copy of the data that it is being passed.
In your destructor, you are trying to array delete (delete [ ]) a static string. You have change your Add function to reserve the string and copy it first. See the code below.
However, if I were you and fairly new to memory management, I'd really use something like CString instead of a raw "char *" as it's much easier to deal with.
void LinkedList::Add(const char *x)
{
Node *nodeToAdd = new Node();
int len=strlen(x);
nodeToAdd->value = new char [len+1]; // room for string + terminating 0
strcpy(nodeToAdd->value,x);
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
value and next in Node class doesn't have memory allocated. You should allocate memory in Node's constructor.