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.
Related
class A
{
public:
A(){ };
~A(){ };
//stuff
};
class B
{
public:
B(A* a){ pA = a;}
~B(){ };
A* pA;
};
int main()
{
A instOfA = A();
B instOfB = B(&instOfA);
return 0;
}
I am unsure as to whether ~B() should delete its pointer data member *pA. I.e.
~B()
{
if(pA!=nullptr) delete pA;
}
My guess is that a deletion is needed because B is allocating it in A* pA.
This is all about the ownership and thereby the question is a design question. You are not dynamically allocating A so I would not let B touch it though. It will be deleted in the end of the main.
If you would allocate an instance of A dynamically (A* instOfA = new A();
), then you could choose if you want to pass the ownership of that instance to B and have B deleting it.
My guess is that a deletion is needed because B is allocating it in A*
pA.
Your guess is not right. B is not allocating A. All it does is to take a pointer of the instance that was allocated in the main.
You're guess is incorrect, since
B instOfB = B(&instOfA);
passes the address of an A of automatic storage duration to Bs constructor. Operator delete can only be safely used to destroy an object that was created with the corresponding operator new. Using operator delete to destroy an object that was NOT created with the corresponding operator new gives undefined behaviour.
instOfA is guaranteed to cease to exist when main() returns, so no action is needed to destroy it. And any action which results in it being destroyed twice (so its destructor is called twice on the same object) also gives undefined behaviour.
Generally speaking, it would often be better to design your class B so it manages the A completely (e.g. manage its lifetime) to ensure consistency. By accepting a pointer, it is not possible to prevent (other than by strident documentation, and relying on programmers heeding the documentation) an object being passed to the constructor that the destructor does not handle correctly.
If you are going to do delete pA, it is not necessary to test that pA is non-NULL. The standard specifies that the delete operator has no effect on a NULL pointer.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Quick question,
I'm new to C++ and I'm having difficulty understanding the destructors.
I'll explain; lets say we have the following;
int _a;
a::a(int x) {
_a = x
}
then we have
a* a1 = new a(8);
I understand that a1's data is created on the heap, and a1 is a pointer, where I'm failing is with the destructor;
a::~a() {
// confusion here
}
Since _a is not a pointer since it was created implicitly on the heap thanks to new (correct) we cannot delete it so what do we do?
Does
delete a1;
call the destructor for a int automatically?
call the destructor for a int automatically?
That would be true if the object were a class type. For non-class types, there is no destrutor, not even implicitly defined ones. Hence, the question of calling the destructor does not arise.
Had your code been something like:
struct Foo
{
Foo() {}
~Foo() {}
};
struct a
{
Foo f
};
a* aptr = new a;
delete aptr;
The destructor, Foo::~Foo(), will be called for f.
I understand what you're driving at and the answer is no, C++ destructors do not automatically destroy the data that your class contains. Unfortunately your example is too contrived to highlight the problem well. int is a primitive type so its destruction is primitive (someone might want to comment on what actually happens in ints destructor). Take the following example:
class A
{
public:
int x;
~A()
{
std::out << "in A destructor" << std::endl;
}
};
class B
{
public:
A* x;
B()
{
x = new A();
}
~B()
{
std::out << "in B destructor" << std::endl;
// does not automatically delete x
}
};
auto x = new B();
delete x;
In this example, constructing an instance of B will also construct an instance of A because you explicitly new it up in the constructor of B. However, unless you explicitly delete x in your destructor for B it will not automatically be deleted.
A slight variation of me previous example would be if B::x were of type A and not A*, in which case the answer is yes, the destructor for A would be called.
I hope this helps!
The destructor is just a function that is called automatically when the instance comes out of scope. It's a convenient way to release dynamically allocated memory.
You don't have to worry about releasing variables that were allocated on the stack (anything that is declared and not new-ed).
For example:
int localStackVar = 5; //no need to deallocate explicitly
int* localPointer = &localStackVar // no need to deallocate explicitly
int* heapValue = new int(); //Allocates to the heap so you need to call delete explicitly
The first two from the example above are on the stack, the first one is an int and the second is an int pointer, which is just a way to say it's a variable that holds the memory address of another variable.
Both of those will be deallocated automatically, since you did not call new on them.
The third line allocates an int on the heap. You have to call delete on it when you don't need it anymore.
If those 3 variables were a part of a class, your constructor and destructors would look like this:
MyClass::MyClass()
{
heapValue = new int();
}
MyClass::~MyClass() //destructor
{
delete heapValue;
}
void someFun()
{
MyClass instance; //constructor is called here
//do stuff
return; //destructor is called here
}
So while MyClass instance is a local stack variable when declared in someFun
since the constructor is called automatically, heapVal is made to point to a memory location that is on the heap which needs to be released explicitly.
If your destructor did not call delete on it, the memory would "leak" it will not be released until your program terminates.
class A
{
int a;
};
class B : public A
{
int b;
};
int main(void)
{
A * p = new B;
delete p; // (1)
return 0;
}
In the above code both classes have default compiler-generated destructors. Both classes also have only Plain Old Data as members so I don't need manually written d'tors which would free any resources. So my question is - after the call in (1) will the default destructor free the entirety of B's instance or will there be any memory leaks? I know that I could use a virtual destructor here but I'm not sure how default d'tors behave.
What you are trying to do invokes undefined behavior, so declaring A destructor as virtual can be considered mandatory.
delete p
Will try to delete p as an instance of A but since the destructor is not declared virtual the correct runtime implementation is not called.
Mind that this doesn't happen when you don't have a pointer but just a concrete object, eg
A a = B();
Because object slicing occurs before, so when a exits the scope it's just an A
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.
class someclass {};
class base
{
int a;
int *pint;
someclass objsomeclass;
someclass* psomeclass;
public:
base()
{
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
throw "constructor failed";
a = 43;
}
}
int main()
{
base temp();
}
In the above code, the constructor throws. Which objects will be leaked, and how can the memory leaks be avoided?
int main()
{
base *temp = new base();
}
How about in the above code? How can the memory leaks be avoided after the constructor throws?
Yes it will leak memory. When the constructor throws, no destructor will be called (in this case you don't show a destructor that frees the dynamically allocated objects, but lets assume you had one).
This is a major reason to use smart pointers - since the smart poitners are full fledged objects, they will get destructors called during the exception's stack unwind and have the opportunity to free the memory.
If you use something like Boost's scoped_ptr<> template, your class could look more like:
class base{
int a;
scoped_ptr<int> pint;
someclass objsomeclass;
scoped_ptr<someclass> psomeclass;
base() :
pint( new int),
objsomeclass( someclass()),
psomeclass( new someclass())
{
throw "constructor failed";
a = 43;
}
}
And you would have no memory leaks (and the default dtor would also clean up the dynamic memory allocations).
To sum up (and hopefully this also answers the question about the
base* temp = new base();
statement):
When an exception is thrown inside a constructor there are several things that you should take note of in terms of properly handling resource allocations that may have occured in the aborted construction of the object:
the destructor for the object being constructed will not be called.
destructors for member objects contained in that object's class will be called
the memory for the object that was being constructed will be freed.
This means that if your object owns resources, you have 2 methods available to clean up those resources that might have already been acquired when the constructor throws:
catch the exception, release the resources, then rethrow. This can be difficult to get correct and can become a maintenance problem.
use objects to manage the resource lifetimes (RAII) and use those objects as the members. When the constructor for your object throws an exception, the member objects will have desctructors called and will have an opportunity to free the resource whose lifetimes they are responsible for.
Both new's will be leaked.
Assign the address of the heap created objects to named smart pointers so that it will be deleted inside the smart pointers destructor that get call when the exception is thrown - (RAII).
class base {
int a;
boost::shared_ptr<int> pint;
someclass objsomeclass;
boost::shared_ptr<someclass> psomeclass;
base() :
objsomeclass( someclass() ),
boost::shared_ptr<someclass> psomeclass( new someclass() ),
boost::shared_ptr<int> pint( new int() )
{
throw "constructor failed";
a = 43;
}
};
Now psomeclass & pint destructors will be called when the stack unwind when the exception is thrown in the constructor, and those destructors will deallocate the allocated memory.
int main(){
base *temp = new base();
}
For ordinary memory allocation using (non-plcaement) new, memory allocated by the operator new is freed automatically if the constructor throws an exception. In terms of why bother freeing individual members (in response to comments to Mike B's answer), the automatic freeing only applies when an exception is thrown in a constructor of an object being new'ly allocated, not in other cases. Also, the memory that is freed is those allocated for the object members, not any memory you might have allocated say inside the constructor. i.e. It would free the memory for the member variables a, pint, objsomeclass, and psomeclass, but not the memory allocated from new someclass() and new int().
I believe that the top answer is wrong and would still leak memory.
The destructor for the class members will not be called if the constructor throws an exception (because it never completed its initialization, and perhaps some members have never reached their constructor calls).
Their destructors are only called during the class's destructor call. That only makes sense.
This simple program demonstrates it.
#include <stdio.h>
class A
{
int x;
public:
A(int x) : x(x) { printf("A constructor [%d]\n", x); }
~A() { printf("A destructor [%d]\n", x); }
};
class B
{
A a1;
A a2;
public:
B()
: a1(3),
a2(5)
{
printf("B constructor\n");
throw "failed";
}
~B() { printf("B destructor\n"); }
};
int main()
{
B b;
return 0;
}
With the following output (using g++ 4.5.2):
A constructor [3]
A constructor [5]
B constructor
terminate called after throwing an instance of 'char const*'
Aborted
If your constructor fails partway then it is your responsibility to deal with it. Worse, the exception may be thrown from your base class' constructor!
The way to deal with these cases is by employing a "function try block" (but even then you must carefully code the destruction of your partially initialized object).
The correct approach to your problem would then be something like this:
#include <stdio.h>
class A
{
int x;
public:
A(int x) : x(x) { printf("A constructor [%d]\n", x); }
~A() { printf("A destructor [%d]\n", x); }
};
class B
{
A * a1;
A * a2;
public:
B()
try // <--- Notice this change
: a1(NULL),
a2(NULL)
{
printf("B constructor\n");
a1 = new A(3);
throw "fail";
a2 = new A(5);
}
catch ( ... ) { // <--- Notice this change
printf("B Cleanup\n");
delete a2; // It's ok if it's NULL.
delete a1; // It's ok if it's NULL.
}
~B() { printf("B destructor\n"); }
};
int main()
{
B b;
return 0;
}
If you run it you will get the expected output where only the allocated objects are destroyed and freed.
B constructor
A constructor [3]
B Cleanup
A destructor [3]
terminate called after throwing an instance of 'char const*'
Aborted
You can still work it out with smart shared pointers if you want to, with additional copying. Writing a constructor similar to this:
class C
{
std::shared_ptr<someclass> a1;
std::shared_ptr<someclass> a2;
public:
C()
{
std::shared_ptr<someclass> new_a1(new someclass());
std::shared_ptr<someclass> new_a2(new someclass());
// You will reach here only if both allocations succeeded. Exception will free them both since they were allocated as automatic variables on the stack.
a1 = new_a1;
a2 = new_a2;
}
}
Good luck,
Tzvi.
If you throw in a constructor, you should clean up everything that came before the call to throw. If you are using inheritance or throwing in a destructor, you really shouldn't be. The behaviour is odd (don't have my standard handy, but it might be undefined?).
Yes, that code will leak memory. Blocks of memory allocated using "new" are not freed when an exception is raised. This is part of the motivation behind RAII.
To avoid the memory leak, try something like this:
psomeclass = NULL;
pint = NULL;
/* So on for any pointers you allocate */
try {
objsomeclass = someclass();
psomeclass = new someclass();
pint = new int();
throw "constructor failed";
a = 43;
}
catch (...)
{
delete psomeclass;
delete pint;
throw;
}
Everything you "new" needs to be deleted, or you'll cause a memory leak. So these two lines:
psomeclass = new someclass();
pint = new int();
Will cause memory leaks, because you need to do:
delete pint;
delete psomeclass;
In a finally block to avoid them being leaked.
Also, this line:
base temp = base();
Is unnecessary. You just need to do:
base temp;
Adding the "= base()" is unnecessary.
you need to delete psomeclass... Its not necessary to clean up the integer...
RWendi