C++ destructor issue with std::vector of class objects - c++

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:
class Test
{
private:
int big[10000];
// no need for constructors, destructor or assignment operator
};
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)

Your problem is here:
Test tObj = Test();
The Test() creates a temporary Test object, which then gets copied to tObj. At this point, both tObj and the temporary object have big set to point to the array. Then the temporary object gets destroyed, which calls the destructor and destroys the array. So when tObj 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, the big 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:
class Test
{
private:
std::vector<int> big;
public:
Test (): big(10000) {}
};
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 integers get allocated and copied whenever you copy an instance of Test.)

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 array big. 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.

Test tObj = Test();
This is wrong and should be as it does not create copies:
Test tObj;
This also create a lot of copies:
vector<Test> tVec;
tVec.push_back(tObj);
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?
class Test
{
private:
int big[10000];
public:
};
This will work fine.

Related

Does the destructor of a class automatically deallocate memory for data members of type char *? C++

Say I have the following class:
class A {
public:
A();
~A();
//...some other functions
private:
char * data;
}
Question 1: Do I have to explicitly define the destructor as the following:
//destructor
A::~A() {
delete [] data;
}
Or, does the compiler do that implicitly?
Question 2: What if I used the same constructed class in main repeatedly inside a loop, does the data member of class A deallocates its memory after each loop? If not, should I do it explicitly?
i.e.:
int main() {
A obj;
for (int i = 0; i < 3; ++i)
getData(obj); //this function will store an input 3 times inside `data`
return 0;
}
The destructor would destroy its own members, sure, BUT, only the member, what it points to is none of its business. In other words, you've to manually clean up whatever you made data to point to. So, yes, you need to explicitly do it in the destructor.
Alternatively, instead of managing this yourself, you can use C++11's std::unique_ptr, in which case, the class destructor would call std::unique_ptr's destructor, which would reclaim the memory you allocated. An SSCCE
#include <memory>
class myClass {
std::unique_ptr<int[]> data;
public:
myClass() : data(new int[5]{1, 21, 9, -1}) { }
};
You don't even need to define a destructor in this case, the default compiler-provided one would do. Read about the new Rule of Zero.
What if I used the same constructed class in main repeatedly inside a loop, does the data member of class A deallocates its memory after each loop? If not, should I do it explicitly?
If you've the scope of your object within the loop body, then yes, every time the variable goes out of scope (the loop ends), the data held by it would be destroyed and the next time gets re-created; this unnecessary and expensive allocation/deallocation can be avoided. You might expose a helper function, say assign that takes in the data you want to replace the old data with and assigns it to the objects pointed to by data. Now you can have A obj outside the loop body and every time inside the loop you need to just assign.
There already is a container in the standard C++ library which does this low-level task of managing the memory: std::vector. I wasn't sure if this is what you wanted, but thanks to Galik for bringing this up. You can use its reserve, assign and other functions to get to an elegant and performant solution.

Caveats and risks of calling a constructor and destructor like common methods?

There's a point in my program where the state of a certain object needs to be reset "to factory defaults". The task boils down to doing everything that is written in the destructor and constructor. I could delete and recreate the object - but can I instead just call the destructor and the constructor as normal objects? (in particular, I don't want to redistribute the updated pointer to the new instance as it lingers in copies in other places of the program).
MyClass {
public:
MyClass();
~MyClass();
...
}
void reinit(MyClass* instance)
{
instance->~MyClass();
instance->MyClass();
}
Can I do this? If so, are there any risks, caveats, things I need to remember?
If your assignment operator and constructor are written correctly, you should be able to implement this as:
void reinit(MyClass* instance)
{
*instance = MyClass();
}
If your assignment operator and constructor are not written correctly, fix them.
The caveat of implementing the re-initialisation as destruction followed by construction is that if the constructor fails and throws an exception, the object will be destructed twice without being constructed again between the first and second destruction (once by your manual destruction, and once by the automatic destruction that occurs when its owner goes out of scope). This has undefined behaviour.
You could use placement-new:
void reinit(MyClass* instance)
{
instance->~MyClass();
new(instance) MyClass();
}
All pointers remain valid.
Or as a member function:
void MyClass::reinit()
{
~MyClass();
new(this) MyClass();
}
This should be used carefully, see http://www.gotw.ca/gotw/023.htm, which is about implementing an assignement operator with this trick, but some points apply here too:
The constructor should not throw
MyClass should not be used as a base class
It interferes with RAII, (but this could be wanted)
Credit to Fred Larson.
Can I do this? If so, are there any risks, caveats, things I need to remember?
No you can't do this. Besides it's technically possible for the destructor call, it will be just undefined behavior.
Supposed you have implemented the assignment operator of your class correctly, you could just write:
void reinit(MyClass* instance) {
*instance = MyClass();
}
You should use a smart pointer and rely on move semantics to get the behavior you want.
auto classObj = std::make_unique<MyClass>();
This creates a wrapped pointer that handles the dynamic memory for you. Suppose you are ready to reset classObj to the factory defaults, all you need is:
classObj = std::make_unique<MyClass>();
This "move-assignment" operation will call the destructor of MyClass, and then reassign the classObj smart pointer to point to a newly constructed instance of MyClass. Lather, rinse, repeat as necessary. In other words, you don't need a reinit function. Then when classObj is destroyed, its memory is cleaned up.
instance->MyClass(); is illegal, you must get a compilation error.
instance->~MyClass(); is possible. This does one of two things:
Nothing, if MyClass has a trivial destructor
Runs the code in the destructor and ends the lifetime of the object, otherwise.
If you use an object after its lifetime is ended, you cause undefined behaviour.
It is rare to write instance->~MyClass(); unless you either created the object with placement new in the first place, or you are about to re-create the object with placement new.
In case you are unaware, placement new creates an object when you already have got storage allocated. For example this is legal:
{
std::string s("hello");
s.~basic_string();
new(&s) std::string("goodbye");
std::cout << s << '\n';
}
You can try using placement new expression
new (&instance) MyClass()

Local variable deletes memory of another variable when going out of scope [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 9 years ago.
While designing a class that dynamically allocates memory I ran into the following problem regarding memory allocation. I was hoping that some of you might be able to point me in the right direction as to how I should design my class in a better way. My class dynamically allocates memory and therefore also deletes it in its destructor.
In order to illustrate the problem, consider the following silly class declaration:
class testClass{
int* data;
public:
testClass(){
data = new int;
*data = 5;
}
~testClass(){
delete data;
}
};
So far so good. Now suppose that I create one of these objects in main
int main(){
testClass myObject;
return 0;
}
Still no issues of course. However, suppose that I now write a function that takes a testClass object as an input and call this from main.
void doNoting(testClass copyOfMyObject){
//do nothing
}
int main(){
testClass myObject;
doNothing(myObject);
return 0;
}
This time around, the function creates a local variable, copyOfMyObject, that's simply a copy of myObject. Then when the end of that function is reached, that local object automatically has its destructor called which deletes the memory pointed to by its data pointer. However, since this is the same memory pointed to by myObject's data pointer, myObject inadvertently has its memory deleted in the process. My question is: what is a better way to design my class?
When you call doNothing(), it is making a copy of your testClass object, because it is being passed by value. Unfortunately, when this copy is destroyed, it calls the destructor, which deletes the same data used by the original instance of testClass.
You want to learn about "copy constructors", and "passing by reference". That is, you should define a copy constructor for your class so that when a copy is made of an instance, it allocates its own memory for its data member. Also, rather than passing by value, you could pass a pointer or a reference to doNothing(), so that no copy is made.
You should create a copy constructor, that is a constructor of the form:
testClass::testClass(const testClass &o)
{
// appropriate initialization here
}
In your case, "appropriate initialization" might mean allocate a new chunk of memory and copy the memory from the old chunk into the new chunk. Or it may mean doing reference counting. Or whatever.
You should also read more about the Rule of Three right here on StackOverflow!
Here's a guideline from an authority: A class with any of {destructor, assignment operator, copy constructor} generally needs all 3
You need a copy constructor that will make a new allocated int for your data, that will then destruct that, but not affect the original.
Alternately, you can make a private copy constructor that's blank, which effectively disables it, forcing your users to pass by reference, or another non-copying way of doing things.

Memory management differences in return by value

I'm trying to follow a tutorial here: regarding overloading operators, and I've found something that's really confused me.
There was a previous question on this very website here where this tutorial was discussed, namely regarding how the variables in the class were preserved because the whole class was passed back by value.
Whilst experimenting with the class definition I toyed with making the integer variables pointers (perhaps not sensible - but just to experiment!) as follows:
class CVector {
int* x;
int* y;
public:
CVector () {};
CVector (int,int);
CVector operator + (CVector);
~CVector ();
};
In the class constructor I allocate memory for the two integers, and in the class deconstructor I delete the allocated memory.
I also tweak the overloaded operator function as follows:
CVector CVector::operator+ (CVector param) {
CVector temp;
*temp.x = *x + *param.x;
*temp.y = *y + *param.y;
return (temp);
}
For the original code, where the class has simple integer variables the return by value of the entire class completes successfully.
However, after I change the variables to int pointers, the return by value of the class does not complete successfully as the integer variables are no longer intact.
I assume the deconstructor is being called when the temporary CVector goes out of scope and deletes these member integer pointers, but the class itself is still returned by value.
I'd like to be able to return by value the CVector with the memory allocated to its member variables intact, whilst ensuring the temporary CVector is correctly deleted when it goes out of scope.
Is there any way this can be done?
Many thanks!
The problem is that you are not following the rule of the three, which basically boils down to: *if you manage resources, then you should provide copy constructor, assignment operator and destructor for your class*.
Assuming that on construction you are allocating memory for the pointers, the problem is that the implicit copy constructor is shallow, and will copy the pointers, but you probably want a deep copy. In the few cases where you do not want a deep copy, control of the manage shared resource becomes more complicated, and I would use a shared_ptr rather than trying to do it manually.
You need to provide a copy constructor for CVector to make copies of the allocated memory. Otherwise, when you return by value, the pointer values will simply be copied and then the temp object is destructed, deallocating the ints. The returned copy now points to invalid memory.
CVector( const CVector& other )
: x ( new int(other.x) )
, y ( new int(other.y) )
{}
Note that it is bad idea to be using raw pointers in your class, especially more than one. If the allocation of y fails above and new throws you've got a memory leak (because x is left dangling). You could've allocated within the constructor itself, instead of the initializer list, either within a try-catch, or using the std::nothrow version of new, then check for nullptr. But it makes the code very verbose and error prone.
The best solution is to use some smart pointer class such as std::unique_ptr to hold pointers. If you were to use std::shared_ptr to hold those pointers, you can even share the ints between copies of the class.
The return-by-value causes the returned, temp object to be copied to another object, a temporary "return object". After temp is copied, it is destructed, deallocating your ints. The easiest way to handle this is to use a reference-counted pointer such as tr1::shared_ptr<>. It will keep the memory allocated until the last reference to it is dropped, then it will deallocate.
There are few problems in the given code.
(1) You should allocate proper memory to *x and *y inside the constructor; otherwise accessing them is undefined behavior.
CVector () : x(new int), y(new int) {}
Also make sure that to have copy constructor and operator = where you delete x and delete y before reallocating them; otherwise it will lead to hazards.
(2) delete them in destructor
~CVector () { delete x; delete y; }
(3) Pass argument to operator + by const reference to avoid unnecessary copying.
CVector CVector::operator+ (const CVector &param)
{
// code
}
Since you are learning with playing around with pointers, I will not comment on the design perspective of your class, like if they should be pointer or variables or containers and so on.

Return vector from function without it being destroyed

I have come across an interesting problem. I have a function in C++ that returns a vector filled with classes. Once the vector is returned, it calls deconstructors for each class that is element in the vector.
The problem is an obvious one: the data is destroyed where a class points to the pointers, which get released when the object is destroyed. I can only assume the deconstructors are called because the vector is on the stack, and not on the heap.
So the question is:
Is there anyway to keep returning vector from a function, without it being destroyed? Or would I have to either pass a pointer to return vector as an input to the function?
You can create anything on heap with new. You shouldn't give out from the function the references to your stack objects, as they will be destroyed as soon as the function finishes.
If you prefer your function to return the vector by value, be sure that the objects inside the vector implement copy constructor (and perhaps assignment operator, too, not sure about that). Having that, please do not forget about the Rule of Three.
C++11 should solve your problem using rvalue references. Honestly, I haven't tried it myself, but from what I read it will do exactly what you are trying to do, return the vector without destroying and recreating it (by passing the memory allocated by that vector on to the new vector instead of having the new vector create its own memory and copy the contents over from the old one).
C++ vectors are allocated on the heap. When you return a vector by value a new one will be created with copies of all the elements, then the original elements will be destroyed.
It sounds like you haven't defined your copy constructors properly. For example:
class ThisIsWrong
{
public:
ThisIsWrong()
{
i = new int;
*i = rand();
}
~ThisIsWrong()
{
delete i;
i = nullptr;
}
int value() const
{
return *i;
}
private:
int* i;
};
void foo()
{
vector<ThisIsWrong> wronglets;
wronglets.push_back(ThisIsWrong());
return wronglets;
}
void main()
{
vector<ThisIsWrong> w = foo();
w[0].value(); // SEGFAULT!!
}
You either need to delete the copy and assignment constructors (which will then turn this into a compilation error instead of runtime), or implement them properly.