I have classes A and B. Class B has a pointer to class A as a field, pointing to a list:
struct A {
A* next;
char* txt;
...};
struct B {
A* next;
int length;
...};
I make each element of this list in this way:
void B::add_elem(char* str) {
A* tmp;
tmp = new A;
tmp->txt = str;
tmp->next = next;
next = tmp;
}
And I have to delete the list at the end. Will it be deleted by default with a destructor of class A, as I've called new A(but I made my destructors to print messages, there were no ones) or should I delete it explicitly (I've tried, it was a mistake in compilation)? Help, please.
B::~B() {
int i;
A* tmp;
cout<<"del list\n";
if (next) { // at least one elem
tmp = next;
while (tmp->next) {
tmp = tmp->next;
delete next;
cout<<"del elem\n";
next = tmp;
}
delete tmp;
}
}
The lifetime of any pointer which is created with new must be managed manually by the creator using a matching delete to free the memory.
This means that every class owning a raw pointer MUST take care of its deletion. This is usually done in the destructor. If you are using C++11 you can use a unique_ptr instead of a raw pointer which will manages his own lifetime. This will help you get rid of many error and memory leaks but will add a few more constraint to your design. In most cases those constraint are what you would actually want to have.
For a nice treatment of the memory management problems in C++ you can take a look at https://isocpp.org/wiki/faq/freestore-mgmt
Oh, it works! It turned out, that I've forgotten to give memory to some field but in the destructor I wanted to delete it. It was a complicated class: some static fields and one dynamic: a dynamic massive, each member of which is a pointer to a list.
At last, this destructor works:
set::~set() {
int i;
elem* tmp;
for(i=0; i<size; i++) {
if (table[i].next) { // at least one elem
tmp = table[i].next;
while (tmp->next) {
tmp = tmp->next;
delete table[i].next;
table[i].next = tmp;
}
delete tmp;
}
}
delete[] table;
cout<<"del set\n";
}
nirvana#lpt00:~/cpp/new$ ./a.out
new set
new list
new list
new list
new list
new list
new el
new el
del el
del el
del list
del list
del list
del list
del list
del set
Thanks everyone!
Related
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.
I'm trying to implement a Singly linked list class in C++. I've overloaded the assignment operator to clone the list. The cloning itself seems to work fine, but the program crashes during deletion of the cloned list, which leads me to suspect if something's wrong during the copy procedure.
Any help is highly appreciated.
Here's the code for the overloaded = operator:
DLList& DLList::operator=(const DLList& iList)
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
return *this;
}
Here's the code for the push operation:
void DLList::push(int data)
{
Node *n = new Node;
n->data = data;
n->next = NULL;
//n->random = NULL;
n->next = _head;
_head = n;
//cout << "_head" <<_head->data<< "head->next" << (_head->next ? _head->next->data : 0)<<endl;
}
Here's the main code (where the crash happens) :
DLList *d = new DLList();
d->push(10);
d->push(20);
d->push(30);
d->push(40);
d->setRandom();
d->display("Original list"); // Displays the original list fine
DLList *d1 = new DLList();
d1 = d;
d1->display("Cloned list"); //Displays the cloned list fine
delete d; // works fine
delete d1; // Crashes here due to segmentation fault, invalid pointer access during delete called as part of destructor)
Code for destructor (if it helps):
~DLList()
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
}
you are not using the assignment operator actually! You are just copying the pointer to the other pointer.
Debugging your code (or just add traces) would have showed that
you were not calling your copy code
the addresses of d and d1 are the same
So when you delete the second list you delete the same address twice.
You don't really need new here:
DLList d;
d.push(10);
DLList d1 = d; // assignment is REALLY called
d1.display("Cloned list");
the objects will be deleted when you go out of scope of your variables
If you want to test in your context, keeping the new, change
d1 = d;
by
*d1 = *d;
to activate assignment operator.
Another advice: factorize your copy code so it is shared between assignment operator and copy constructor, and the deletion code should be shared between destructor and assignment operator (to avoid memory leaks when assigning twice): Not tested, don't flame me if it doesn't compile, just tell me I'll fix it, I'm already overanswering here :)
DLList& DLList::operator=(const DLList& iList)
{
destroy(); // or you'll get memory leaks if assignment done twice
copy(iList);
return *this;
}
DLList& DLList::DLList(const DLList& iList)
{
_head = NULL; // set _head to NULL in all your constructors!!
copy(iList);
}
~DLList()
{
destroy();
}
void DLList::copy(const DLList& iList) // should be private
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
}
void DLList::destroy() // private
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
_head = NULL; // calling destroy twice is harmless
}
d1 = d; is NOT copying DLList. Instead, you just make d1 point to the list that d pointing to. So, both d1 and d are pointing to the same list. At the end of your program, you will delete the list twice, and make your program crash.
If you wish to use the assignment operator, you need to dereference your pointers. See here:
DLList *d1 = new DLList();
d1 = d; // <------------- This line
d1->display("Cloned list"); //Displays the cloned list fine
On the highlighted line, you're setting the pointer d1 to point to the same location as d. This means that when you call delete at the end of your code, you're trying to delete the same object (d in this case) twice.
To fix your code, you should dereference your pointers:
DLList *d1 = new DLList();
*d1 = *d; // <------------- Note the dereference applied to BOTH lists.
d1->display("Cloned list"); //Displays the cloned list fine
Alternatively, you should avoid using pointers entirely if you can. For your trivial example you could simply create your objects directly.
Your problem is the statement
d1 = d;
which does a pointer assignment, and makes d1 point to the same object as d. The subsequent delete statements cause the same object (*d) to be released twice. That is undefined behaviour (of which one symptom is a crash like you describe).
The above also does not invoke DLLists copy constructor. If that is your intent, you need to do
*d1 = *d;
which makes the object pointed to by d1 a copy of the one pointed to by d. The two delete statements are also appropriate in this case.
I'm trying to learn C++ and there is a small confusion I have.
The text which I am learning from tells me that if I want to delete a node of type const T& I should first create a new pointer of that node type, then delete it using the inbuilt C++ delete[]. However, what happens if I just set the link from the to-be-deleted node's previous element to the to-be-deleted node's next element? Something like:
*p = node.previous;
p-> next = node.next;
Or will this cause a memory leak?
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Node<T> *p = node-to-be-deleted;
delete p;
What is the best way to delete the node?
Assuming your node looks like this:
struct Node
{
Node* previous;
Node* next;
SomeType data;
};
Then:
*p = node.previous;
p-> next = node.next;
Then YES. This will cause a memory leak.
It also leaves p->next->prev pointing at the wrong node.
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Yes the best way is to "never delete pointers". But this has to go along with some context. You should not be deleting pointers manually because pointers should be managed by an objects that control their lifespan. The simplest of these objects are smart pointers or containers. But for this situation that would be overkill (as you are creating the container).
As you are creating the container (a list) you will need to do the management yourself (Note C++ already has a couple of lost types std::list for a list of values of type t or boost::ptr_list for a list of pointers to T). But it is a good exercise to try and do it yourself.
Here is an example on code review of a beginner making a list and the comments it generated:
http://codereview.stackexchange.com: Linked list in C++
I hope this helps in explains on how to create and delete objects.
Node* p = new Node; // This is how you allocate a node
delete p; // This is how you delete it
The delete[] operator should be used on dynamically allocated arrays:
Node* nodelist = new Node[ 4 ]; // nodelist is now a (dynamically allocated) array with 4 items.
delete[] nodelist; // Will delete all 4 elements (which is actually just one chunk of memory)
Deleting a Node directly only makes sense if Node implements a destructor to update the previous and next pointers of the surrounding Node instances, eg:
Node::~Node()
{
if (previous) previous->next = next;
if (next) next->previous = previous;
}
Node *p = node-to-be-deleted;
delete p;
Otherwise, you have to update the Node pointers before then deleting the Node in question, eg:
Node *p = node-to-be-deleted;
if (p->previous) p->previous->next = p->next;
if (p->next) p->next->previous = p->previous;
delete p;
With that said, the best approach is to no implement a linked list manually to begin with. In C++, use a std::list container instead, and let it handle these details for you.
void deleteNode( Node * p )
{
Node * temp = p->next;
p->data = p->next->data;
p->next = temp->next;
free(temp);
}
Heres something i did a few months ago.
template <class T>
T LinkedList<T>::remove(int pos)
{
if (pos < 1 || pos > size)
{
throw pos;
}
ListNode * temp;
if (pos == 1)
{
temp=head;
head = head->next;
}
else
{
int i=1;
ListNode * prev = head;
while(i<pos-1)
{
i++;
prev=prev->next;
}
temp = prev->next;
prev->next = (prev->next)->next;
}
--size;
return temp->item;
}
I have this test program. I don't know how to delete struct in the list using iterator.
#include<iostream>
#include<list>
using namespace std;
typedef struct Node
{
int * array;
int id;
}Node;
void main()
{
list<Node> nlist;
for(int i=0;i<3;i++)
{
Node * p = new Node;//how to delete is later?
p->array = new int[5];//new array
memset(p->array,0,5*sizeof(int));
p->id = i;
nlist.push_back(*p);//push node into list
}
//delete each struct in list
list<Node>::iterator lt = nlist.begin();
while( lt != nlist.end())
{
delete [] lt->array;
delete &(*lt);//how to delete the "Node"?
lt++;
}
}
I know how to delete the struct separately. It's like this:
Node * p = new Node;
p->array = new int[5];
delete [] p->array; //delete the array
delete p;//delete the struct
However, when it is pushed back into list, I don't know how to delete it according to the list iterator.
list<Node>::iterator lt = nlist.begin();
while( lt != nlist.end())
{
delete [] lt->array;
delete &(*lt);//how to delete the "Node"?
lt++;
}
You could use the list erase to delete a node from anywhere in between the list.
list<Node>::iterator it = nlist.begin();
advance(it,n); \\n is the node you want to delete, make sure its less than size of list
it = mylist.erase (it);
Alternatively, if you want to delete elements from either ends of the list you can use the
pop_back or the pop_front member functions.
Since you are declaring the list with list<Node> when you do:
nlist.push_back(*p)
it is actually creating a Node() and copying the data from the node you just dynamically allocated but not using the actual pointer. And then you try to delete a pointer from the object that the system will automatically delete:
delete &(*lt); // this causes double free
You need to declare the list like list<Node*> so that the pointer is inserted into the list. Although you should not really deal with this kind of allocation in c++, with a couple of modifications your code should work:
int main()
{
list<Node*> nlist;
for(int i=0;i<3;i++)
{
Node *p = new Node;//how to delete is later?
p->array = new int[5];//new array
memset(p->array,0,5*sizeof(int));
p->id = i;
nlist.push_back(p);//push node into list
}
//delete each struct in list
list<Node*>::iterator lt = nlist.begin();
while( lt != nlist.end())
{
delete [] (*lt)->array;
delete *lt;//how to delete the "Node"?
lt++;
}
return 0;
}
use list.erase
But you are really doing that non-c++ way. You do not need allocate int[5] with new. Writing int[5] does what you want. Your Node type defined in c-way. In c++ you do not need to wrap it with typedef
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.