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
Related
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.
I came across some odd code like the following:
class B {
int* ab;
///...
~B() { /// not virtual
delete ab;
}
///...
}
class D : public B {
int* ad;
///...
~D() {
delete ab;
delete ad;
}
///...
}
But in my opinion, the destructor of the subclass will definitely call the destructor of its base class. So, I think there is no need for the subclass to deallocate resources allocated by its base class. Thus, there is no need to add delete ab in the destructor of class D. What's worse, delete one object twice is wrong.
However, this code works fine in our systmem for a very long time and passes our whole test cases. Are there any other considerations in this kind of odd implementation?
So I wander, if the destructor of subclass is called, then ,no matter what happened, the destructor of base class will be called later on.
Or, after the execution of subclass's destructor, is there any way to stop the execution of base class's destructor?
You are correct that the B class destructor will be called if the a D instance is destructed. The call to delete ab; in the D dtor is a bug.
The other thing to consider with this code, is that because B's dtor is not virtual you cannot delete an instance of D via a B pointer.
The DTOR for D is incorrect in both cases though, and should definitely be changed. If you plan on using the hierarchy of classes polymorphically then you also must change the B DTOR to be virtual.
We know that it is needed to specify the destructor of a base class as virtual if you intend to use it polymorphically, otherwise you might have a ressource leak in your program, since only the base class destructor will be called and not the derived object destructor.
We also know that constructors / destructors are purely initialization / uninitialization constructs, and operator new / operator delete handle the allocation / unallocation of memory.
In that case, why exactly does the lack of destructor-calling incur a leak, in the case where my C++ class contains only primitive data members?
Would it be more accurate to say that the operator delete cannot unallocate the memory, and that is what creates a resource leak?
EDIT: Adding an example, to clarify my question. In the following case, the derived destructor never gets called. Does it mean that the memory for derivedInt never gets unallocated? In that case, is it because the destructor cannot be called, or because the operator delete cannot unallocate the memory for the int?
class Base
{
int baseInt;
public:
Base(){};
~Base(){};
};
class Derived : public Base
{
int derivedInt;
public:
Derived(){};
~Derived(){};
};
int main(int argc, const char * argv[]) {
Base *pb = new Derived();
delete pb;
return 0;
}
Deleting an object through pointer to base invokes undefined behavior unless the destructor in the base class is virtual. Source
This means anything can happen - including a memory leak.
Does the default destructor in C++ classes automatically delete members that are not explicitly allocated in code? For example:
class C {
public:
C() {}
int arr[100];
};
int main(void) {
C* myC = new C();
delete myC;
return 0;
}
Does delete myC deallocate myC's arr automatically? Or do I need to write C's destructor to do this explicitly?
The constructor (in the absence of any ctor-initializer-list) calls the default constructor for each subobject.
Since you have no base classes and your member variables are primitive types, it will do nothing at all.
Same with the destructor. Yours is implicitly compiler-generated since you haven't declared one, and it will call the destructor for each subobject. Again that's trivial because your only subobject is an aggregate of primitives.
Now, all memory of the class will be freed when you delete it. Since the array is embedded inside the class, it's part of the same memory region and will be freed at the same time.
The implicitly defined (default) destructor will call the destructor for each member. In the case of a member array, it will call the destructor for each element of the array.
Note that pointers don't have destructors; you need to manually delete them. You don't have this problem in the provided example, but it's something to be aware of.
If your class/struct contains a pointer, and you explicitly allocate something for that pointer to refer to, then you normally need to write a matching delete in the dtor. Members that are directly embedded into the class/struct will be created and destroyed automatically.
class X {
int x;
int *y;
public:
X() : y(new int) {}
~X() : { delete y; }
};
Here X::x will be created/destroyed automatically. X::y (or, to be technically correct, what X::y points at) will not -- we allocate it in the ctor and destroy it in the dtor.
Anything that you call new for must have a corresponding delete. If you didn't call new to create an instance of something then you don't have to call delete.
You don't have to write a destructor. C++ class has the default destructor to delete the object after 'return 0' to recycle the memory.
#include<iostream>
using namespace std;
class A
{
public:
int i;
A() {cout<<"A()"<<endl;}
~A() {cout<<"~A()"<<endl;}
};
class B:public A
{
public:
int j;
B(): j(10)
{
this->i=20;
this->~A();
}
};
int main()
{
B abc;
cout<<"i="<<abc.i<<" j="<<abc.j<<endl;
}//main
Two questions:
How come A's destructor gets called like an ordinary function instead of destroying the object? (or is it some kind of rule that the base class will be destroyed only if the child class's destructor calls the base class's destructor?) I was trying out this sample code to find out how the destructor works. So if simply calling the destructor function does not destruct the object, then there is obviously some other kind of call that calls the destructor and only then the object is destructed. What's so special in that kind of call and what call is it?
Is there a way to have an initialization list for A in B's constructor? Something like this:
class B:public A
{
B(): j(10), A():i(20) {}
};
Destructor is like any other normal function which you can call (but you should never do it unless you use a placement new). When you call delete on a object two things happen: Destructor is called for cleanup and then operator delete is called to release the memory allocated for the object. Here the second step is not happening.
No, you can not call it like that. What you can do is some thing like this:
class A
{
public:
A(int n) : i(n){}
};
class B : public A
{
public:
B() : A(20), j(10){}
};
The base class's destructor should be virtual. Here, as it's created on the stack, it's not problem, but anyway..
No, but you can call the class A() constructor in the initialize list of B's constructor, like this:
B(): A( .. ), ...
A* a = new B();
//..
delete a;
will not call B's destructor unless class A destructor is virtual. That's why STL containers should not be derived - theirs destructors are not virtual.
#Nav: no, your understanding of "destroyed" is just wrong. When an object's destructor is called, the object is destroyed. You seem to believe that the memory it resided in evaporates entirely, but that never happens. The object no longer exists, but some garbage data is typically left over by the object, and if you're willing to break the rules of C++ and invoke undefined behavior, then you can read those leftover bytes, and they'll look like the object, and because there are no runtime checks on whether you're accessing a valid object, you can often treat them as an object. Which you do.
It's illegal, it's undefined behavior, but in practice it often works.
Once again, a destructor does not physically vaporize the memory. Your RAM still has the same capacity after a destructor has executed. Conceptually, the object no longer exists once the destructor has run. But the data it contained is still there in memory.
For point:
This is an undefined behaviour but only ~A() is called though an instance of class B because ~A() is not declared virtual. See more on Wikipedia.
No. For derived classes, first call your parent class, then assign parameters.
For point 1) on Wikipedia:
having no virtual destructor, while
deleting an instance of class B will
correctly call destructors for both B
and A if the object is deleted as an
instance of B, an instance of B
deleted via a pointer to its base
class A will produce undefined
behaviour.
Example (for point 2):
B(): A(), j(10) {}
or
B(): A() {j = 10;}
1) Destructor calling order in C++ is reverse order of the constructor calling order. So first derived class object get destroy and then base class object.
2) No.
In the code that you are giving, you are indeed destroying the base class and as such i. Calling a destructor and then using the dead object is undefined behavior - it may work or it may crash.
Should i was something that is more complex that an int (for example a vector), trying to do anything with that would probably result in a crash.
If you call ~SomeClass() yourself, explicitly, the destructor function will be called. Which leaves the object (in this case, the base class part of the object) in a destroyed state.
Since the destructor is not virtual, the destructor of derived classes will not be called, but base classes of SomeClass will be destroyed too.
Trying to find out if A is really destroyed by just using the i member, is not a good test. In fact, you can't test this, since using the object results in undefined behavour. It may work, or it may not (in your case, it probably will print "i=20 j=10", but i is already destroyed).