This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
When to use virtual destructors?
[Second dicuss]
hi,guys! You are all talking about virtual-destructor.
And also i think about the base class`s destructor.
But another test as this:
class A
{
public:
A()
{
}
virtual void fun()
{
}
private:
int mIntA;
};
when class A have a vitual function(not virtual-destrcutor),
it`s ok. Deleting ptrA is OK!
So, i think A just need a vptr to activate the polymorphic. Not class As
destructor must be virtual.
Class As destructor being not virtual just can make resources is not released
correctly.
class A
{
public:
A()
{
}
/*virtual*/ ~A()
{
}
private:
int mIntA;
};
class B : public A
{
public:
B()
{
mIntB = 1234;
}
virtual ~B()
{
int i = 0;
}
private:
int mIntB;
};
I have a class A. And a class B derived form A;
A doesn`t have any virtual function.
so when i do this:
A* ptrA = new B;
delete ptrA;
it crashes!
but when add a virtual fun to A. it`s ok.
as we know, ptrA is a B object.
but why is it?
The A class isn't polymorphic, therefore the delete has no possibility to know that ptrA actually points inside an allocated block and therefore the deallocation crashes.
You have a non-virtual destructor!
(which means that when the destructor is called, it's A's destructor that is called, rather than B's, even though the object was allocated as a B)
Related
Example:
class Base {
public:
virtual void f() = 0;
virtual ~Base() { std::cout << "Base::~Base()\n"; }
};
class Derived : public Base {
public:
void f() { }
~Derived() { std::cout << "Derived::~Derived()\n"; }
};
int main() {
Base* p = new Derived();
delete p;
return 0;
}
Output:
Derived::~Derived()
Base::~Base()
I thought only the derived class destructor will be called since the pointed object to be freed is an instance of the derived class.
I have two questions:
Why was the virtual base destructor called?
Is it legally possible (or should it even be possible) to prevent the base class destructor from being called?
Why was the virtual base destructor called?
Because base class should be properly destructed. Derived class can not possibly do this.
Is it legally possible (or should it even be possible) to prevent the
base class destructor from being called?
No, because it would prevent properly destructing the base class (i.e. call it's members destructors)
Say we have the classes.
class A
{
public:
void doSomething() = 0;
A();
virtual ~A();
private:
vector<SomeStuff> cont;
bool yesNo;
}
class B: public A
{
public:
B();
~B();
private:
bool Byesno;
}
So the constructor of A gets called first and then the constructor of B gets called after that, and when we destroy B, the destructor of B gets called first and the destructor of A gets called after that. So basically, the destructor of A will delete the inherited variables of B and and the destructor of B will delete its class-specific ones. Am I right?
what I don't understand is how can we call the destructor of A if we can't even instantiate an object of type A? How does it work internally?
B is A and some more. Destructor of A will be called to ensure that A part of B is cleaned up. Your classes don't use the virtual keyword, so I'm not sure why you are wondering about virtual destructors, but since you are wondering this might help:
class A
{
public:
virtual ~A() { cout << "A::~A()" << endl; }
};
class B : public A
{
public:
~B() { cout << "B::~B()" << endl; }
};
int main()
{
A* obj = new B();
delete obj;
return 0;
}
The output as you'd expect will be
B::~B()
A::~A()
But, if you didn't declare A's destructor virtual, the output will simply be
A::~A()
So, in conclusion, if your code involves polymorphism and you want the destructor of the pointed to object to be called as opposed to the destructor of pointer's type itself, you will have to declare your base-class destructor virtual.
Each destructor runs through three stages:
user code
delegate destruction of class members to the respective destructors
delegate destruction of base classes to the respective destructors
The destructors for the primitive types are normally trivial, i.e. do nothing. Technically, you could think of
B::~B() { Byesno = false; }
as
B::~B()
{
Byesno = false; // explicit
Byesno.~bool(); // implicit, member
A::~A(); // implicit, base class
}
A::~A()
{
yesNo.~bool(); // implicit, member
cont.~vector(); // implicit, member
}
~bool() is empty and will be inlined, so the only call you can see is the one to ~vector().
All this is a separate matter from which d'tor is called. If A's d'tor is non-virtual, B's d'tor will be called only if the object being destructed is known to be a B object:
A a;
B b;
A *ap = new B;
delete ap;
This will use ~A() for the a object (correct), ~B() for the b object (also correct), and ~A() for the object pointed to by ap (incorrect, but we don't know better). If ~A() were virtual, the d'tor call itself would be looked up in the v'table, which contains a pointer to ~B() then.
It is a tiny bit more complex than that, but not much.
Is it ok to delete an abstract class instead of a child? Will all allocs be deallocated thereby?
Consider a following situation as an example, but please do not limit your answers to that one case:
struct A {
virtual void fun() = 0;
};
struct B : public A {
void fun() { /* actually doing something here. */ }
};
struct C {
A *a;
void OneTask() {
// (...)
a = new B();
}
void AnotherTask() { /* using fun() in some way. */ }
~C() { delete a; }
};
The idea is to have multiple possible outcomes of OneTask() which result in an assignment of a pointer to different classes that inherit from A, B being just an example; and then to use such result reasonably in AnotherTask() and other methods of class C.
You must have virtual destructor in base class else complete destruction of derived class doesn't happen.
struct A {
virtual void fun() = 0;
virtual ~A()
{
}
};
Yes, it's perfectly fine to delete a without knowing what actual derived type a is pointing to.
As shivakumar pointed out, if you don't make your base class's destructor virtual, then deleting a derived class will not end up calling the base class's destructor. In your trivial example that's not a problem, but in real life you should always make your destructors virtual.
If A has a virtual destructor then both destructors of A and B are succesfully called (first B then A) ,
If you do not declare the constructor of A as virtual, then only the destructor of A is called during deletion and extended data of B may leak.
struct A {
virtual void fun() = 0;
virtual ~A();
};
struct B : public A {
void fun() { /* actually doing something here. */ }
~B();
};
#include <iostream>
using namespace std;
class base
{
int a;
public:
base() {a =0;}
};
class derv :public base
{
int b;
public:
derv() {b =1;}
};
int main()
{
base *pb = new derv();
delete pb;
}
I don't have a virtual destructor in derv class, does it delete only base part of derv object??
It might.
Because base does not have a virtual destructor, your code exhibits undefined behavior. Anything might happen. It might appear to work as you expect. It might leak memory. It might cause your program to crash. It might format your hard drive.
A citation was requested. C++11 ยง5.3.5/3 states that, for a scalar delete expression (i.e., not a delete[] expression):
if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the
static type shall have a virtual destructor or the behavior is undefined.
The static type (base) is different from the dynamic type (derv) and the static type does not have a virtual destructor, so the behavior is undefined.
In your source code there is no memory leak, since you don't have any member variable that is created dynamically.
Consider the modified example below Case 1:
#include <iostream>
using namespace std;
class base
{
int a;
public:
base() {a =0;}
~base()
{
cout<<"\nBase Destructor called";
}
};
class derv :public base
{
int *b;
public:
derv() { b = new int;}
~derv()
{
cout<<"\nDerv Destructor called";
delete b;
}
};
int main()
{
base *pb = new derv();
delete pb;
}
In this case the output will be,
Base Destructor called
In this case there is a memory leak, because 'b' is created dynamically using 'new' which should be deleted using 'delete' keyword. Since derv destructor is not being called it's not deleted so there is memory leak.
Consider the below case 2:
#include <iostream>
using namespace std;
class base
{
int a;
public:
base() {a =0;}
virtual ~base()
{
cout<<"\nBase Destructor called";
}
};
class derv :public base
{
int *b;
public:
derv() { b = new int;}
~derv()
{
cout<<"\nDerv Destructor called";
delete b;
}
};
int main()
{
base *pb = new derv();
delete pb;
}
In the case 2 output will be,
Derv Destructor called
Base Destructor called
In this case there is no memory leak.because derv destructor is called and b is getting deleted.
Destructor can be defined as Virtual in base class to make sure the derived class destructor to be called when we delete base class pointer which is pointing to derived class object.
We can say 'Destructor must be virtual when derived class has dynamically created members'.
There is no memory leak in your code. There would have been a memory leak if you needed to free some memory in the derived class destructor.
I have a base class A and a derived class B:
class A
{
public:
virtual f();
};
class B : public A
{
public:
B()
{
p = new char [100];
}
~B()
{
delete [] p;
}
f();
private:
char *p;
};
For any reason the destructor is never called - why? I dont understand this.
Your base class needs a virtual destructor. Otherwise the destructor of the derived class will not be called, if only a pointer of type A* is used.
Add
virtual ~A() {};
to class A.
Class A should have a virtual destructor. Without that, derive class destructors won't be called.
try this:
class A
{
public:
virtual ~A() {}
virtual f();
};
class B : public A
{
public:
B()
{
p = new char [100];
}
virtual ~B() // virtual keywork optional but occasionally helpful for self documentation.
{
delete [] p;
}
f();
private:
char *p;
};
If your variable is of type A it doesn't have a virtual destructor and so it won't look at the actual runtime type of the object to determine it needs to call the desstructor
Add an empty destructor to A
virtual ~A() {}
and that should fix it.
In general you need to do this on any class that can possibly be used as a base class.