C++ Memory Leak using list class and push_back
void EMAdd(int n)
{
list<Employee*> em;
for (int i = 1; i <= n; i++)
em.push_back(new Employee());
}
Q1. at the end , the destructor of class list automatically deletes the nodes of em?
Q2. But why this function still has a memory leak?
Thanks,
I would appreciate your answer!
The destructor of Employee is not called. You have a list of pointers to Employee objects, not a list of Employee objects. When the list's destructor is called it will destroy the pointers to the Employee object, but not the objects they point to which you created with new Employee(). They will still be in memory but the only references to them are lost when the list is destroyed, leaking that memory.
Remember every call to new must have a matching call to delete somewhere. However, better yet don't use pointers at all and simply use a list of Employee objects directly.
void EMAdd(int n)
{
list<Employee> em;
for (int i = 1; i <= n; i++)
em.push_back(Employee());
}
Since each element in std::list is already dynamically allocated, a list of pointers is redundant and essentially gives you a set of pointers to pointers.
You should have a list of unique_ptrs so that the memory will be freed upon destruction:
std::list<std::unique_ptr<Employee>> em;
But as David Brown said, you shouldn't be using pointers to begin with.
Related
If I have class and vector of pointers in class how should I write destructor to properly free memory?
Is it correct?
~Class()
{
for(int i = 0; i<v.size(); i++)
{
delete v[i];
}
}
Or should I also erase elements from vector? Or any other solutions?
~Class()
{
for(int i = 0; i<v.size(); i++)
{
delete v[i];
v.erase(e.begin() + i);
}
}
If I have class and vector of pointers in class how should I write destructor to properly free memory? Is it correct?
It depends.
Do the pointers point to objects that were allocated with new and is this class the owner of those dynamic objects (i.e. is this class responsible for their destruction)? If not, then it's not correct.
Or should I also erase elements from vector?
Your example for erasing elements of the vector is wrong. It will skip half of the elements and thus will not call delete all pointers. After first iteration, first element will have been erased, so the next element has been shifted to the index 0, but next loop deletes and erases the element in index 1.
There's no point in erasing elements of the vector, because it is immediately about to be destroyed.
Or any other solutions?
If you intend for the class to own dynamically allocated objects, prefer using a vector of objects instead of pointers. If you need a vector of pointers for example to allow run time polymorphism, then use a vector of std::unique_ptr. That way you don't need to implement a destructor as the automatically generated would be just fine.
If your class is to supposed to own the objects pointed to, then its sufficient to do:
for (auto p : v) delete p;
If the vector itself is the member of the class then its elements are getting deleted when the class instance object is destroyed, you dont need to do this manually.
And in your example you are also doing it wrong. If its a std::vector you could just call vector's clear() method. Otherwise you would call delete[] p; where p is the pointer to the vector elements itself.
I am not allowed to use Vectors specifically for this school assignment. Most of the answers I've found simply state "you should use vectors" as the most up-voted comment. While I appreciate and understand this, I'm simply restricted from using them for this assignment.
It is a C++ assignment with dynamic memory management as follows:
// property in header declaration
int numAnimals;
int capacity;
Animal** animals;
void addAnimal(Animal *newAnimal);
// class implementation
capacity = 10;
numAnimals = 0;
animals = new Animal*[capacity];
void SampleClass::addAnimal(Animal *newAnimal)
{
for (int i = 0; i < capacity; i++){
if(animals[i]){
// animal object already exists in array, move on
i++;
}else{
animals[i] = newAnimal;
numAnimals++;
break;
}
}
}
animals is a pointer to a pointer, in this case a pointer to an array of pointers to object type Animal which have yet to be created.
With the 'addAnimal' function, what I'm trying to do is add an animal object to the array by looping through the array of pointers, and if there already exists an animal object, iterate to the next index. If there is no animal, then insert that animal into the array.
I'm getting an exception thrown "read access violation" when I attempt to access a member function of an animal object in the array.
My suspicion is because:
if(animals[i]) probably isn't doing what I think it's doing, running it through the debugger I never hit the 'else' portion, so the array is still full of pointers not set to any objects when the method is complete. Therefore, when I try to access a member function, it's of an object that doesn't exist.
So, if my suspicions are correct, then what is the best way to insert a new object into an array of pointers in this fashion? They need to be pointers otherwise it automatically creates the array full of populated objects, which is not what I want.
I didn't post all of the code because I wanted to keep my problem brief, apologies I'm a new to C++ and stackoverflow in general. Yes, I know to delete[] to clear memory afterwards.
Any help is appreciated, thanks!
Since in numAnimals you keep count of the current number of animal pointers in the array, you don't need the for loop to find the first available slot to add a new animal pointer (note also that, assuming you want to use a for loop like shown in your code, you have to pay attention to properly initialize all the initial pointers in the array to nullptr).
You can just use:
// Inside SampleClass::addAnimal(Animal *newAnimal):
animals[numAnimals] = newAnimal;
numAnimals++;
Please note that you have to pay attention to not overflow your array capacity, when you insert a new animal.
So, before inserting a new animal, you have to check that there's enough room in the array, e.g.:
// Before inserting:
if (numAnimals == capacity)
{
// You ran out of capacity.
//
// 1. Allocate a new array with bigger capacity (e.g. 2X)
// 2. Copy the content from the current array to the new one
// 3. delete current array
}
As a side note:
Yes, I know to delete[] to clear memory afterwards
Note that if you call delete[] on the animals array of pointers, you release this pointer array, but not the Animal objects pointed to.
int capacity = 10;
Animal** animals = new Animal*[capacity];
This allocates ten pointers, except it does no initialization,
meaning you have essentially garbage data.
if (animals[i])
This test one of those pointers against nullptr, but since you did
no initialization, it's not very likely that it's nullptr.
You need to add a loop-pass that null out the data, right after you
allocate it:
for(int i=0; i<capacity; ++i)
animals[i] = nullptr;
There is also a bug:
if (animals[i]) {
// animal object already exists in array, move on
i++; // <- here
This is wrong, you move on twice for (int i = 0; i < capacity;i++)
The thing is "Use a vector", despite your teacher telling you otherwise, is the correct way to do it. However, if you are supposed to manage the dynamic array manually, then the best you can do is to encapsulate all that dirty memory stuff inside a class and write your own replacement for std::vector. Ie to avoid having dynamic allocations spread all over your code (especially in places that are supposed to deal with Animals and shouldnt care about manually allocating memory and the like) you should write a class that does that (and nothing else) and provides a nicer interface. I can only outline the idea here:
template <typename T>
class my_vector {
private:
T* data;
size_t size;
size_t capacity;
public:
void push_back(const T& t);
size_t size();
T& operator[](size_t index);
void resize(size_t size);
//... etc...
};
I have had a good look at some other questions on this topic and none of them (to my knowledge) address how to correctly erase items from a stl list of objects which contain dynamicically assigned memory vs. a stl list of objects that don't contain dynamically assigned memory.
I want to use a list of objects. Take this object for example (which contains no dynamically assigned memory):
class MyPoint {
public:
MyPoint(int _x,int _y)
{
x = _x;
y = _y;
}
private:
int x;
int y;
};
So I might create a list of objects (not pointers to them), add things to it and then erase an element:
list<MyPoint> myList;
myList.push_back(MyPoint(3,4));
myList.push_back(MyPoint(1,2));
myList.push_back(MyPoint(8,8));
myList.push_back(MyPoint(-1,2));
list<MyPoint>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
My list now contains:
(3, 4)
(1, 2)
(-1, 2)
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
Ok, now consider an alternative version of the class that allowed a point in N-dimensional space. I.e., I could dynamically assign an array of length N to hold the N points inside the class (I have spared you the implementation as that is not in question here). The destructor of the class would then delete the dynamically assigned array using 'delete'.
class MyDynamicPoint {
public:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete points;
points = NULL;
}
private:
int *points;
};
I might now create a list of pointers to the objects, instead of the objects themselves:
list<MyDynamicPoint*> myList;
myList.push_back(new MyDynamicPoint(8));
myList.push_back(new MyDynamicPoint(10));
myList.push_back(new MyDynamicPoint(2));
myList.push_back(new MyDynamicPoint(50));
list<MyDynamicPoint*>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
QUESTION 2a - Is the above correct? I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Many thanks in advance for any help,
Best,
Adam
When you have a class with data members that have automatic storage duration (i.e. their lifetime is tied to the instance of this class) like this:
class MyPoint {
private:
int x;
int y;
};
and you will use list<MyPoint> myList;, then this instance of std::list is also an object with automatic storage duration, that will be cleaned up automatically and by the time the container is destructed, so are the elements it holds. Everything is taken care of.
But the latter version is not very lucky choice... not only that you have a container holding pointers, you even decided to create a data member of class Point that will be allocated dynamically. At first note that everything that has been allocated by calling new should be freed by calling delete and everything allocating by calling new[] should be freed by calling delete[].
In this situation, you are allocating the memory when the object is constructed and cleaning it up when the object is destructed:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete[] points;
points = NULL;
}
private:
int *points;
You would achieve the same by using some std::vector or std::array instead of the C-style array and you wouldn't have to take care of the memory management on your own:
MyDynamicPoint(int N) : points(std::vector<int>(N, 0)) { }
private:
std::vector<int> points;
the std::vector object will take care of memory management for you.
And last thing: when you dynamically allocate an element and store it into the container:
myList.push_back(new MyDynamicPoint(8));
you need to free this memory on your own, erasing the pointer from the list is not enough:
list<MyDynamicPoint*>::iterator it;
...
delete *it;
myList.erase(it);
So whatever you want to achieve, always prefer objects with automatic storage duration if the situation allows it. There's nothing worse than being forced to taking care of memory management manually and dealing with unpleasant problems such as memory leaks later.
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
You don't need to do anything.
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
You don't need to do anything.
QUESTION 2a - Is the above correct?
The code is not correct. You're violating The Rule of Three. In particular, the automatically-generated MyDynamicPoint's copy constructor and assignment operator will make a bitwise copy of the points pointer. If you copy an instance of MyDynamicPoint, you'll end up with two object sharing the same points pointer:
When one of the objects goes of scope, the other becomes unusable.
When the second object goes out of scope, its destructor will attempt to free memory that's already been freed. This is undefined behaviour.
I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
No, it does not mean that. In fact, you should probably continue to store objects by value. However, you do need to fix the rule of three.
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Since you have a list of raw pointers, the destructors will not be called automatically. The easiest way to fix that is to either store objects by value, or use std::unique_ptr or std::shared_ptr instead of raw pointers.
To question 1, there is nothing you need to do. As you store the objects by value the compiler and the library will handle everything.
However, when you store pointer as in the second case, you need to delete those pointers that you have allocated with new, or you will have a memory leak.
And you have to delete the pointers before doing the erasing, as that can invalidate the iterator:
delete *it;
myList.erase(it);
I think following should work
MyPoint* ptr = myList.back();
delete ptr;
myList.pop_back();
OR
MyPoint* ptr = myList.back();
delete ptr;
myList.erase(ptr);
I am working on a project as a homework for my university course of Systems Programming.
I got really confused with the matter of Pointers, Vectors, stacks and heaps.
Using C++.
I have to get a vector of objects which are courses, and those courses objects have several different fields.
What I did was this:
vector<CoursesObject> coursevector;
and then I created my Courses Object class, which contains the space left in course and name of course fields.
Now I want to add a new course, I do:
CoursesObject *theCourse = new CoursesObject(name, space);
now I want to add it to the handler vector:
coursevector.push_back(*theCourse);
With all I know, I created a vector of Courses objects on the stack, and made a new pointer to a new course that is on the heap, and added to the handler vector the pointer theCourse that points to the course object in the heap. Is what I said correct?
When I try to delete those course objects, I do:
for(int i=0; i<coursevector.size(); i++)
delete coursevector.at(i);
which gives me an error that it is not a pointer. But haven't I added to the coursevector a POINTER to the course object?
Please somebody explain, I have to handle the memory correctly and it seems that I am not getting it right.
This
vector<CoursesObject> coursevector;
is a vector of CourseObjects, so it cannot hold CourseObject pointers. When you do this:
coursevector.push_back(*theCourse);
you get a copy of the CoursesObject pointed at by theCourse stored in the vector. You do not need to delete any entries from the vector. In fact, you can't, because it doesn't hold pointers.
You program would be much simpler if you just avoided the dynamic allocation:
coursevector.push_back(CoursesObject(name, space));
You do not need to use new at all.
//This vector stores CoursesObject objects,
//not pointers to CoursesObjects.
vector<CoursesObject> coursevector;
//Construct theCourse with automatic storage
//duration.
CoursesObject theCourse(name, space);
//Copy theCourse into coursevector
coursevector.push_back(theCourse);
//theCourse will be automatically destroyed.
//coursevector (and all the objects that it contains)
//will be automatically destroyed.
all of your objects are not dynamically allocated, so you cannot delete them at any time during the program. Remember that you can only delete object once they are dynamically allocated:
int Var1 = 0; //cannot be deleted, scope and life will exist for the life of program
int * Var2 = new int; //CAN be deleted, dynamically allocated.
delete Var2; //free memory
You can however delete your last object, which is a pointer. I would grab the last element of the vector and call delete on it(which should be your pointer to the class).
when you do this:
coursevector.push_back(*theCourse);
actually you are dereferencing the pointer theCourse, so you are adding a copy of the object. You need to declare a vector of CourseObject pointers:
vector<CoursesObject *> coursevector;
Then you add an object:
coursevector.push_back(theCourse);
Now your code to delete the objects should work:
for(int i=0; i<coursevector.size(); i++)
delete coursevector.at(i);
coursevector can hold only CoursesObjects and not pointers to CoursesObjects, so you needn't use the new operator (check #Mankarse's answer). But, if you still want to hold pointers, then change the definition of coursevector to
vector<CoursesObject*> coursevector;
and push_back the value of the pointer as it is:
coursevector.push_back(theCourse);
vector< int > vect;
int *int_ptr = new int(10);
vect.push_back( *int_ptr );
I under stand that every "new" needs to be followed by a "delete" at some point but does the clear() method clean this memory?
What about this method of doing the same thing:
vector< int > vect;
int int_var = 10;
vect.push_back( int_var );
From what I understand, clear() calls the variables destructors, but both vect.push_back() methods in this example push an object on the vector, not a pointer. so does the first example using an int pointer need something other than clear() to clean up memory?
The first method leaks because the vector never takes ownership of the allocated pointer. In fact, it doesn't contain a pointer at all, only a copy of the value.
The second method does not leak, as no memory is dynamically allocated (except internally in the vector -- it will handle that memory itself).
When you push_back on a vector, you add a copy of the data to the vector. Therefore, in both cases, the original data still needs to be freed. In the first case, you need to delete it; in the second, it will be "freed" by the stack pointer as it goes out of scope.
Vectors make copies on push_back. Since a pointer is 'just another variable' (but one that happens to point to memory), when you push_back an integer pointer that has been previously allocated, you copy the pointer's value into the vector, causing a potential dangling pointer, since there will be two pointers pointing at the same spot in memory.
In your first example, you would need to delete the memory manually. One strategy I've used in the past for meddling with graph classes is to have something like this (vast amounts of stuff redacted due to being at work and typing quickly):
class graph //quick-format
{
vector<node*> nodes;
add_node(node n)
{
node *temp = new node;
*temp = n;
nodes.push_back(temp)
}
~graph()
{
for(int i = 0; i < nodes.size(); i++)
delete nodes[i];
}
};
As a caveat, graph's copy semantics will have to be examined. As it stands, it will result in deleting previously-free'd memory. The advantage is that you can always have the same set of nodes hanging around. Caveat Emptor, like any direct memory usage..
However, if you simply push a non-pointer variable, there is no possibility of memory leaking from your end. Possibly the vector will leak, but... that is practically impossible at this point in the maturity of the tools.