This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Does std::list::remove method call destructor of each removed element?
Assume I have this:
void f(...)
{
.
.
std::list<X*> xList;
.
// Then i fill the list
std::list<X*>::iterator iter;
for (iter = xList.begin(); iter != xList.end(); ++iter)
{
*iter = new X();
}
}
When xList goes out of scope, I know that the container should call the destructor of the objects that are contained within the list? First, is that true?
If so, then since the list contains pointers to class X shouldn't the destructor ofX be called when xList goes out of scope? Thus freeing any memory that was held by X?
Yes and no.
Each elements' destructor will be called.
However this won't result in the effect you want. The elements are of type X*, thus the destructor of X* will be called (which does nothing for pointer type) rather than destructor of X that you need. You need to explicitly delete your elements. In general, if you have new in your code, there should be a corresponding delete.
In C++ standard library design a container is the only owner of the contained elements so when the container is destroyed all elements are destroyed.
However note that "destroying" a naked pointer in C++ is a no-operation so the pointed-to element will not be deleted (a naked pointer may point to statically allocated data or to data that is owned by some other container).
What you can do is creating either an std::list of the elements (instead of pointer to the elements) or (in case you need a pointer because of, for example, polymorphism) you can instead use smart pointers that can take care of the pointed elements if you like so.
Related
This question already has answers here:
What do I need to do before deleting elements in a vector of pointers to dynamically allocated objects?
(5 answers)
Does std::vector call the destructor of pointers to objects? [duplicate]
(3 answers)
Closed 8 years ago.
If I have a std::vector of something (say,does std::vector::clear() call destructor of the content? For example, if I have a data as vector, is the following code valid?
char * pd;
for(vector<char *>::iterator it = data.begin(); it != data.end(); ++it) {
pd = *it;
delete pd;
}
Or, is it redundant as data.clear() would do that? I presume not, i.e. manual deallocation of the content is needed. I presume, data.clear() will not call implicit destructor for the contents? Is it correct? This is for pre C++11.
To answer your title: std::vector<T>::clear() does call the destructor for each element. However, for primitive datatypes like char* the destructor is trivial (standardese for "does nothing") which is practically the same as if no destructor is called.
Note: A destructor is not the same as the delete operator.
So what your question should be: "Does std::vector<T*>::clear() call delete on its elements?" and here the answer is: No, it does not call delete. You have to do it manually like shown in your example code, or you can (and probably should) use objects like std::string or smart pointers instead of raw pointers. Those do the memory management for you, and their destructors (which get called, see above) call the delete for you.
If your items are dynamically allocated and your vector contains pointers to them, you will have to manually call delete on each pointer in that container before calling clear(). Otherwise you have a memory leak.
If they are objects that are not dynamically allocated then you do not need to do anything - the destructor (if there is one) of the objects in the vector will be called when the vector is cleared.
std::vector clear() does call the destructor of each element in the vector:
http://www.cplusplus.com/reference/vector/vector/clear/
But in your case it won't delete the contents of your dinamically allocated memory. I suggest using string instead of char*
This question already has answers here:
Does std::list::remove method call destructor of each removed element?
(6 answers)
Closed 9 years ago.
I have a class that contains pointers, the class inherits nothing
class MyClass
{
public:
MyClass();
~MyClass();
private:
//i have pointers here
};
MyClass::~MyClass()
{
print("destroyed..");
}
Now i have to use this class as a pointer in vector like this:
vector<MyClass*> classes;
Push some classes in here but when i remove an element:
classes.remove(index);
The destructor doesn't get called,and i think that I have a memory leak.
So how do i make it call the destructor
A vector of pointers does nothing to delete the pointers when they get removed or cleared from it. The vector cannot know if the pointers are dynamically allocated or not. It is not it's job to call delete.
It is up to you to call delete on the pointers, if and when it is necessary. There are not enough details in your question to determine whether it is necessary at all (you haven't shown how the objects pointed to are allocated). But since you claim there is a memory leak, this could indicate that they are dynamically allocated. The immediate solution is to call delete:
delete *it;
classes.erase(it); // vector has no remove member function
A safer solution is to store unique ownership smart pointers, such as std::unique_ptr<MyClass>. The standard library also provides smart pointers for shared and weak ownership. See Smart Pointers.
All the above is assuming that you do actually need to store a pointer. In general, it is safer and clearer to store values:
std::vector<MyClass> classes; // but don't call it "classes". A vector stores objects.
That's one of the reasons why you should avoid using std::vector<MyClass*> at first place. There's an ugly memory management connected with it and it won't stay as easy as classes.remove(index);
Basically, for every new a delete must be called and for every new[] a delete[] must be called, no matter whether you use this pointer as a local variable or you put it into the vector:
vector<MyClass*> vec;
vec.push_back(new MyClass()); // <-- object has been created
...
delete classes[index]; // <-- object shall be destructed
// the delete call will automatically invoke the destructor if needed
...
// now you can remove the dangling pointer from the vector
Just note that once the object has been destructed, any (old) reference to this object is invalid and trying to access this object using such reference (dangling pointer) will yield undefined behavior.
Firstly, std::vector has no remove, you probably mean erase.
Secondly, you need to manually call delete on whatever you're removing:
vector<MyClass*> classes;
auto iter = <iterator to index to remove>;
delete *iter;;
classes.erase(iter);
Or, to avoid all this pain, use a std::unique_ptr<MyClass>.
It is unclear who is responsible for managing the lifetime of the objects pointed by the pointers inside classes. Have you pushed newed pointers into it, or have you pushed the addresses of automatic storage objects?
If you have done the former, then you must manually delete the pointer before removing it. Else, if you have done the latter, then you could just leave it as is, just leaving the pointed-to objects destroy themselves as they leave their respective scopes. If you have mixed newed and non-newed pointers, whose possibility isn't that remote as you would think, then you're definitely damned, undefined behavior making demons fly out of your nose.
These kinds of situations involving pointers are very ambiguous, and it is generally recommended not to use pointers at all, and make the std::vector store plain objects, which makes your object lifetime management much simpler and the making the declaration just speak for itself.
vector<MyClass> classes; // Do this instead
You have to manually delete your pointers before your application exit or after your class object is removed from vector.
// Delete all
vector<MyClass*>::iterator it = classes.begin();
while (it != classes.end()) {
delete *it;
it = classes.erase(it);
}
Tip: Never add stack constructed pointers like following:
MyClass m;
classes.push_back(&m);
Edit: As suggested by other member the better solution is:
MyClass m(/* ... */);
vector<MyClass> classes;
classes.push_back(m);
However please note, you have to properly implement the copy constructor especially if your class has pointer data members that were created with new.
Make a temp pointer to hole MyClass* pointer before you remove it from your vector.
vector<MyClass*> classes;
//push some classes in here but
//when i remove an element
MyClass* temp = classes[index];
classes.remove(index);
// call delete temp; if you want to call the destructor thus avoid memory leak.
delete temp;
To avoid memory leak, remember never to loose control of heap object, always keep a a pointer or reference to it before object release.
It seems that you want your vector to be manager of your items.
Take a look at boost::ptr_vector class
its basically a wrapper around std::vector class.
You declare that this vector is the "holder" of these pointers, and if you remove them from this containers you want them to be deleted.
#include <boost/ptr_container/ptr_vector.hpp>
...
boost::ptr_vector<MyClass> myClassContainer;
myClassContainer.push_back(new MyClass());
myClassContainer.clear(); // will call delete on every stored object!
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);
In C++ what happens if you create an object on the stack (within a function) and insert it into a heap-allocated container (which has been passed into the function/exists after the function finishes)?
The stack object has local scope, but the container it has been inserted within, is on the heap and can last after the function (where the insert was made) has returned. Is the stack object still retrievable from the container after the function returns?
void Test( std::vector<MyClass>& myvec )
{
MyClass m;
myvec.push_back(m);
}
In this particular case, m will be copy-constructed into a new instance of MyClass, which will be owned by the vector. So a different but equivalent instance of MyClass can be retrieved from the vector, yes.
Base assumption: when you use Vector, you really mean std::vector. The answer could change with a container that's designed enough differently.
As long as you do like you usually should, and store objects (not pointers) in the container, you're all right, because what's stored in the container is normally a copy of the object you pass.
Under the right circumstances, the object in the container can be move constructed from what you pass, but the effect is basically the same -- you end up with an object whose lifetime continues until it's removed from the container (or the container is destroyed, etc.)
Is the stack object still retrievable from the container after the function returns?
Yes, your myvec.push_back(m); makes a copy of m and a new copy is manged by vector.
However, after your function returns myvec doesn't have m inside because you pass myvec into Test function by value, Test function makes a temporary copy of myvec and copy m into it, after function returns the temporary copy of myvec is released. So you meant to pass myvec to Test function by reference as below:
public void Test(Vector<MyClass>& myvec){
MyClass m;
myvec.push_back(m);
}
As noted by other answers, m is copied into vector. That said, your function receives vector by value too (UPD: it was true for the original code, which was edited since), and it's obviously not what you wanted.
The code in the question will create a copy of MyClass in the std::vector. The original m will be destructed when the Test method exits.
If we change the vector to store pointers to MyClass we have two possible options.
void Test( std::vector<MyClass*>& myvec )
{
// Allocates a new MyClass on the heap.
MyClass* pM = new MyClass();
myvec.push_back(pM);
// This variable will be allocated on the stack and cleaned up on method exit
MyClass dontDoThis;
myvec.push_back(&dontDoThis);
}
At the end of this method myvec has two elements, myvec[0] and myvec[1].
When a container of pointers is stored then the object must be allocated so that it is valid for the length of time the pointer is in the container. In the example above the pM pointer will be valid after the Test method exits. This means that myvec[0] will be a valid pointer after the method exits.
Initially, a valid pointer to dontDoThis variable will be added to the vector, but when the method exits the destructor of dontDoThis will be called and the memory will probably be used to store other data. The pointer in myvec looks ok, but any attempt to actually use it will cause undefined behaviour. On method exit the pointer in myvec[1] might look valid, but actually it points to junk.
Note that at a later time, when myvec[0] is changed or deleted, it is important to call:
delete myvec[0]
to ensure that the object is cleaned up properly. Otherwise a memory leak will occur.
After explaining what will happen with naked pointers, I strongly recommend you use smart pointers such as std::unique_ptr and std::shared_ptr
Is the stack object still retrievable from the container after the function returns?
Only if MyClass has a "gut" copy constructor. (Deep copy or sharing ownedship of other resuorses, etc)
I mean, it could be retrived but it could be in a broked state
I have a std::vector of Element*. When will the destructor be called.
How is it different if it is a vector of Element
std::vector<Element*> vect;
..
struct Element
{
Record *elm;
Element(Record *rec)
{
elm = new Record();
//...copy from rec
}
~Element()
{
delete elm;
}
};
I am using the vector as follows:
Element *copyElm = new Element(record);
vect.push_back(copyElm);
In the above code, how can I ensure there's no leak.
You could use a reference-counting pointer-wrapper class in your array, and the items will automatically get deleted whenever there are no more references to them. One such class is boost::shared_ptr. You will also find it in some compiler's shipping C++ libraries because it is being added to a future version of C++.
std::vector<boost::shared_ptr<Element> > vect;
These classes wrap operator ->, etc, so you can use them in most of the same ways that you'd used a normal pointer.
http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/shared_ptr.htm
Whenever you free the class Element instance yourself. The vector will free the vector elements (the pointers), but not the class Element objects pointed to. After all, the vector has no way to know if you have other pointers to the same object.
vector will call release the memory of the object it is holding (i.e. pointers) but will not release the memory of the object it is pointing to. You need to release the memory of the Element object yourself. If it was a vector<Element> then whenever you do a push_back a copy of the element is inserted into the vector. vector guarntess that it will release the memory allocated to this copied object. But be aware with the current definition of Element you will get a seg fault as you have not defined the copy ctor and assignment operator.
EDIT
If you for some reason don't want to use smart pointers, then only option is to write a release function which goes through the entire vector and calls the delete on the stored pointer.
In a vector of Element, the destructor is called a lot. Whenever a node is assigned, the vector is sized down, the vector has to move in memory, or the vector goes out of scope/is destroyed, destructors are called on the elements before they are changed/discarded. Also, the copy constructor is called for assignment, and the default constructor is called to initialize each entry. Sorting such a vector will involve a lot of both copying and destroying.
In a vector of Element* it is never called, unless you call delete yourself.
Take a look at Boost shared_ptr for a saner solution, or unique_ptr if you have a compiler with relatively new features.
Destroying a pointer is always a no-op, and there are several good reasons why.