Memory deallocation of class inside of another class - c++

I am trying to understand how to give back memory if one class creates another class.
I have
Clas A;
Then another class that allocate memory for Class A:
class B{
private:
A* data;
public:
// Allocating new memory
B (){
A* data = new A();
//giving memory back
~B(){
delete data; };
};
And when I execute the code in main function it just crashes. What am doing wrong? I am a bit lost here.
Thanks.

Get rid of the redundant A* in the constructor. What this does is create a new, local variable with the same name as your class member. So the real B::data never gets anything assigned to it, and when you try to delete it, things blow up. To add insult to injury, the new A() you assign to the local data will be leaked (well; it would be leaked if the program didn't crash).
class B{
private:
A* data;
public:
// Allocating new memory
B (){
data = new A();
}
//giving memory back
~B(){
delete data;
}
};
That solves the immediate problem, but as juanchopanza noted in the comments, you will still run into problems if you try to copy this object.

Here's the RAII / Rule of Zero route (assuming your compiler supports C++11)
class A {};
class B {
private:
std::unique_ptr<A> data;
public:
B() : data(new A) {
}
};
The RAII handle in this case a unique_ptr will take care of deallocation for you. Implementing it this means the compiler defined copy constructor, copy assignment operator, move constructor, move assignment operator and destructor will all work fine right out the box.

Related

Deleting an Object in c++ implies deletion of its members?

I am quite new to c++ and I have a question.
If I have a class containing a (pointer to a) vector:
class myClass {
public:
int* direction;
myClass(int d){direction=new int[d];}
}
When I create an object and delete it in the main:
int main(){
int d;
myClass* myvec;
myvec = new myClass(d);
delete myvec;
}
Also the destructor for myvec->direction has been coherently called and the memory freed? Or do I have to write an apposite method for that?
I hope the question is clear...
If you've allocated memory with new you need to delete it too, like this:
class myClass {
int* direction;
public:
myClass(int d) : direction(new int[d]) {}
~myClass() {
delete[] direction;
}
}
But you'd also need to write a copy constructor and copy assignment operator, and in C++11 and later also a move constructor and move assignment operator, for this to be working good. Otherwise, you'd risk the default versions of those copying the raw pointer when you use instances of this class.
Take a look at the rule of three/five/zero.
You'd be much better off using a std::vector<int> instead of a raw pointer.

Should I use unique_ptr to keep class' members?

I have such code:
class A
{
public:
A(void);
~A(void)
{
delete b;
delete c;
delete d;
// ...
}
private:
B* b;
C* c;
D* d;
// ...
};
//A.cpp
A(void) : b(new B()), c(new C()), d(new D()) //...
{
}
Class A takes ownership over own objects b, c, d ...
What is the best way to keep these objects? I guess, that usage of std::unique_ptr<B/C/D> type will be suitable for this way. For example, it allows to don't care about carefull writing of destructor.
it allows to don't care about carefull writing of destructor.
More than that.
Your code is not exception-safe. For example, if new D() failed by exception being thrown, delete b and delete c won't be executed and memory will leak, because destructor won't be called if constructor fails. Smart pointers can help you to avoid this kind of situation.
Holding raw pointer as members you need to implement destructor carefully, and copy constructor and assignment etc too. See What is The Rule of Three? and Rule-of-Three becomes Rule-of-Five with C++11?.
Best is to keep everything by value. If it fits*, and does not need to be hidden**. If it does not fit or needs to be hidden first preference is std::unique_ptr***, second preference (if ownership has to be shared) is std::shared_ptr. And only as a last resort (example for which I cannot even think up). You would actually have raw pointers and manage lifetime yourself, with risk of memory errors and leaks.
* - sometimes you want to be able to have parent object on stack by value and child objects are, say, large arrays which, if stored by value would overflow the stack
** - sometimes you don't want to show what child objects really are (because they are complex, say boost.fusion adapted classes. Then you would want some form of PIMPL idiom:
class.hpp
struct b;
struct A { std::unique_ptr<b> b_; A(); ~A(); }
class.cpp:
struct b { ... }
A::A() = default;
A::~A() = default;
*** - automatic management of dynamically allocated members with unique_ptr
struct A {
std::unique_ptr<b> b_;
A(...):
b_(std::make_unique<b>(...)) {}
};
I think it's worth mentioning that if you do not want to transfer ownership, you must use const std::unique_ptr. Using a non-const std:unique_ptr allows to transfer it to another std:unique_ptr.

Creating a 'new' instance solves destructor crash?

I created a sub-class, B, for a class that I'll call A.
I wrote this code for work, so I'm going to generalize the actual code:
class A
{
public:
A ()
{
important_variable = new Type();
...
};
~A (void) { delete(important_variable); }; // Default destructor
// more methods
protected:
Type *important_variable;
};
class B : public A
{
public:
B() : A() { important_variable = another_var; }
~B() {};
Type *another_var;
};
Having this code for B caused my program to crash with an 'Unhandled Exception'.
Now, when I change the code for class B to this:
class B : public A
{
public:
B() : A() { another_var = new Type(); important_variable = another_var; }
~B() {};
Type *another_var;
};
The exception goes away.
I think that my original code for B caused my program to crash because A was trying to delete a variable that was still being pointed to by another variable. Is this reasoning correct? Why does the new code for B cause my program to work?
There are many flaws in your code, but the one most likely to cause a crash is this line:
important_variable = another_var;
another_var does not point anywhere that can be deleted. But important_variable is made to point to the same place, and then is deleted in A's constructor.
Your "solution" masks the problem, at the cost of a memory leak. When you do this
another_var = new Type(); important_variable = another_var;
the original dynamically allocated Type object that important_variable pointed to is lost.
Besides that, you need to follow the rule of three.
new and delete are for handling heap allocations only. I suspect that in your first listing of class B, another_var is likely allocated on the stack and this is what is causing the exception in the destructor. Additionally, whenever you have a base class you really should make its destructor virtual.
The original version crashed because you set important_variable to uninitialised another_var and then you tried to delete this uninitialised value.
In the "corrected" version you at least do not delete uninitialised variables, but still in contains memory leak - you assign newly allocated memory to important_variable and then immediately you assign to this variable the value of another_var, so the originally allocated memory is no longer accessible and will leak.

Behaviour of Inheritance when class includes copy constructor and assignment operator

I am not able to understand this behavior. I have a class A,
class A
{
public:
int ch;
char *s;
A()
{}
A(char *st):ch(0)
{
s = new char[10];
strcpy(s,st);
}
A(const A& rhs):ch(rhs.ch)
{
s = new char[strlen(rhs.s)+1];
strcpy(s,rhs.s);
}
const A& operator=(const A& rhs)
{
char *temp = new char[strlen(rhs.s)+1];
strcpy(temp,rhs.s);
delete[] s;
s=temp;
ch = rhs.ch;
return *this;
}
~A()
{
delete []s;
}
};
Till this point everything goes as expected I am able to test my copy constructor and assignment operator and they are working properly.
Now I created a child class B and I am getting heap corruption error. I am not able to understand, is this the problem related somewhere with class A destructor. ?
Below is my class B,
class B:public A
{
public:
int a;
B():a(0){}
};
You default constructor for A does not initialise the member s (a pointer):
A()
{}
Hence when elements are constructed using this constructor, you get a crash when the destructor deletes the uninitialized element:
~A()
{
delete []s;
}
Class B uses the default constructor for A, and therefore triggers this problem. Avoid it by properly initializing all members in the default constructor:
A() : ch(), s(0)
{ }
To solve your problem all you need to do is to replace:
char *s;
with
std::string s;
Just get rid of the manual memory management through char *, this is precisely the reason C++ provides you with std::string.
What might be the problem?
Your default constructor which does not take any arguments does no dynamic allocation.
If you created the class object through this constructor, Your destructor ends up deleteing a pointer which was not allocated with new and thus resulting in Undefined Behavior.
In the destructor, you delete[] s;, but in the default constructor, you haven't new[]ed s. In fact, you haven't even initialized s.
The default constructor of the base class is called when you instantiate the derived class because you have not initialized the base otherwise (: A(...)). Therefore, you have no idea what you're deleting, or even what you're going to have for breakfast tomorrow, because it's undefined behaviour.
To keep it consistent, new[] s in the default constructor. To save headache, I would suggest something like std::string instead of character pointers.

STL Vectors, pointers and classes

Let's say i have 2 classes:
class Class1
{
public:
std::vector<CustomClass3*> mVec;
public:
Class1();
~Class1()
{
//iterate over all the members of the vector and delete the objects
}
};
class InitializerClass2
{
private:
Class1 * mPtrToClass1;
public:
InitializerClass2();
void Initialize()
{
mPtrToClass1->mVec.push_back(new CustomClass3(bla bla parameters));
}
};
Will this work? Or the memory allocated in the InitializerClass2::Initialize() method might get corrupted after the method terminates?
Thanks!
In short this will work fine.
The memory being allocated in Initialize is on the heap. This means that changes in the stack do not affect the contents of this memory.
One issue I see with Class1 is that it is not copy safe yet the copy and assignment constructors have not been suppressed.
This can cause a problem because the destructor of Class1 is noted as freeing the memory for all items in mVec. Using the implicit operator this means that you'd end up with 2 instances of Class1 pointing to the same CustomClass3 instances and the second destructor would be double deleting memory. For example
Class c1;
c1.mVec.push_back(new CustomClass3(...));
Class c2 = c1;
In this case the second destructor to run (c1) will be freeing an already deleted CustomClass3 instance. You should disable copy construction and assignment for Class1 to prevent this
class Class1 {
...
private:
Class1(const Class1&);
Class1& operator=(const Class1&);
};
It should work (provided mPtrClass1 is a valid pointer of course).
May I suggest that in your InitializerClass2 that you change the constructor to the following:
InitializerClass2() : mPtrToClass1(NULL){}
~InitializerClass2(){
if( mPtrToClass1 != NULL) delete mPtrToClass1;
}
void Initialize(){
if( mPtrToClass1 == NULL){
mPtrToClass1 = new InitializerClass1();
}
mPtrToClass1->mVec.push_back(new CustomClass3(bla bla parameters) );
}
if you're not going to use RAII, so that you don't get issues with checking the destructor.
As to your question, see where I added in the new operator. YOu're not initializing your variable.