I am confused about how to use destructors when I have a std::vector of my class.
So if I create a simple class as follows:
class Test
{
private:
int *big;
public:
Test ()
{
big = new int[10000];
}
~Test ()
{
delete [] big;
}
};
Then in my main function I do the following:
Test tObj = Test();
vector<Test> tVec;
tVec.push_back(tObj);
I get a runtime crash in the destructor of Test when I go out of scope. Why is this and how can I safely free my memory?
The problem is you don't define a copy constructor for
Test
. So the compiler generates a default copy constructor for you, which just copies the content of the object - in this case the int pointer.Now, when you push back your object into the vector, it is implicitly copied with the copy constructor. Which results in two objects pointing to the same array of ints! So in the end, two destructors try to delete the same array - BANG.
Whenever you define a class which owns members via pointers*, apart from the destructor you must also define a copy constructor for it. Update: and an assignment operator, for the same reason (thanks @James :-)
Update2: A trivial way to get around all these restrictions is to define a static array instead of the dynamically allocated one:
However, the best practice is to use
std::vector<int>
instead of an array.* that is, contains pointers to members with ownership semantics (thanks to @Steve Jessop for clarification)
Without a copy-constructor, the vector will create a flat copy of your object. This leads to two objects of type
Test
referencing the same arraybig
. The first instance deletes the array when it gets destroyed, and then the second instance try to dereference a deleted pointer, which is undefined behavior.Your problem is here:
The
Test()
creates a temporaryTest
object, which then gets copied totObj
. At this point, bothtObj
and the temporary object havebig
set to point to the array. Then the temporary object gets destroyed, which calls the destructor and destroys the array. So whentObj
gets destroyed, it tries to destroy the already-destroyed array again.Further, when
tVec
is destroyed, it will destroy its elements, so the already-destroyed array will be destroyed yet again.You should define a copy constructor and an assignment operator so that when a
Test
object gets copied, thebig
array gets copied, or has some sort of reference count so that it doesn't get destroyed until all owners are destroyed.An easy fix is to define your class like this:
In this case, you wouldn't need to define any destructor, copy constructor, or assignment operator, because the
std::vector<>
member will take care of everything. (But note that this means 10,000 bytes get allocated and copied whenever you copy an instance ofTest
.)This is wrong and should be as it does not create copies:
This also create a lot of copies:
So if you free one int array, you'll free all the arrays. And the following delete will fail.
What you need is either:
use a copy constructor to have for each class a separate array
Why use a pointer?
This will work fine.