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();
};
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)
I have a class that has a std::vector of pointers to a base class that has different derived classes. How do I call their destructors from within the vector class?
holder.h
class holder
{
public:
void add_stuff();
void do_stuff();
private:
std::vector<base*> vect;
};
holder.cpp
void holder::add_stuff(base* to_add) {
vect.push_back(to_add);
}
void holder::do_stuff() {
vect[0]->say_words();
delete vect[0]; //<--<--<-- I want to delete the object now
}
Feel free to stop now if you know what I'm doing wrong. I've included the basics of what the rest of the code looks like, in case I'm just way off.
base.h
class base
{
public:
base();
virtual ~base();
virtual void say_words() = 0;
};
derived.h
class derived : public base
{
public:
derived();
~derived();
void say_words();
};
derived.cpp
derived::derived() {}
derived::~derived() {}
void derived::say_words() {
cout << "Words!" << endl;
}
main.cpp
holder hold;
holder* H = &hold;
int main(){
base* d = new derived();
H->add_stuff(d);
H->do_stuff();
}
How do I call their destructors from within the vector class?
You already are, by virtue of the fact that the ~base destructor is marked as virtual. Calling delete on a pointer to the base class will automatically call all of the derived destructors for you. That is WHY the base class destructor needs to be declared as virtual in the first place.
What you are missing, though, is removing the object pointer from your std::vector after you delete the object, eg:
void holder::do_stuff() {
vect[0]->say_words();
delete vect[0]; // <-- calls all destructors of this object!
vect.erase(vect.begin()); // <-- add this line!
}
You don't want to leave invalid pointers in your container.
I have a inheritance that the destructor of base class applies Template Method Pattern. The destructor has to do some works before calling the virtual clean function, and do some another works after calling.
We know that Never Call Virtual Functions during Construction or Destruction. So the following code definitely is not available.
class base
{
public:
virtual ~base()
{
// ... do something before do_clear()
do_clear();
// ... do something after do_clear()
}
private:
virtual void do_clear() = 0;
};
class d1
: public base
{
public:
d1() : m_x(new int) {}
~d1() {}
private:
virtual void do_clear()
{
delete m_x;
}
int *m_x;
};
But if I moved the destruction of process to the destructor of derived class, for example:
class base
{
public:
virtual ~base()
{
}
protected:
void clear()
{
// ... do something before do_clear()
do_clear();
// ... do something after do_clear()
}
private:
virtual void do_clear() = 0;
};
class d1
: public base
{
public:
d1() : m_x(new int) {}
~d1()
{
clear();
}
private:
virtual void do_clear()
{
delete m_x;
}
int *m_x;
};
If the client write that:
base *x = new d1;
delete x;
It will call ~d1(), then call base::clear(), eventually call the virtual function d1::do_clear() properly.
The base::clear() can been moved to public, and the client can make things safely by calling base::clear() before destruction. A precondition is the client must know and not forget to call, I think it isn't convenient and breaks encapsulation.
My question is:
Is the design dangerous/risk?
Is existing other better design for this?
There are two problems with your current design. The first is that it violates the rule of five/rule of zero. This means that ordinary usage of these classes is almost certain to result in memory leaks or double deletions.
The second problem is that you are using inheritance to model something that is probably better modelled with composition. base wants d1 to provide some extra functionality to its destructor, with the exact form of this functionality specified at run-time. The use of a replaceable interface is therefore internal to base, and so should not be externally visible.
Here is how I would write this code (using wheels::value_ptr):
struct D_interface {
//Providing virtual functions for run-time modifiable behaviour
virtual D_interface *clone() const = 0;
virtual ~D_interface(){}
};
struct D_Delete {
//Here is the code to call through to the virtual `D` object behaviour:
void operator()(D_interface *p) {
// ... do something before delete p;
delete p;
// ... do something after delete p;
}
//Put (pointers to) relevant data here,
//initialise them when constructing the `value_ptr`, or
//at a later stage with get_deleter
};
struct d1 : D_interface {
wheels::value_ptr<int> mx;
virtual D_interface *clone() const {
return new d1(*this);
}
};
//Nothing derives from `base`, because the polymorphism that is needed is internal
//to the implementation of `base`
//To add new functionality, add a new `D_interface` implementation.
class base
{
wheels::value_ptr<D_interface, wheels::DefaultCloner<D_interface>, D_Delete> D_impl;
public:
base(D_interface *D_impl)
: D_impl(D_impl)
{
}
};
For my part I think that this pattern it is sure because you need to implement the virtual function in the derived classes. This is the philosophy of virtual classes.
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)
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.