Do interfaces need a virtual destructor, or is the auto-generated one fine? For example, which of the following two code snippets is best, and why? Please note that these are the WHOLE class. There are no other methods, variables, etc. In Java-speak, this is an "interface".
class Base
{
public:
virtual void foo() = 0;
virtual ~Base() {}
};
OR...
class Base
{
public:
virtual void foo() = 0;
~Base() {} // This line can be omitted, but included for clarity.
};
EDIT DUE TO "NOT WHAT I'M LOOKING FOR" ANSWERS:
Exactly what are the consequences of each route. Please don't give vague answers like "it won't be destructed properly". Please tell me exactly what will happen. I'm a bit of an assembly nerd.
Edit 2:
I am well aware that the "virtual" tag means that the destructor won't get called if deleted through a pointer to derived, but (I think) this question ultimately boils down to "is it safe to omit that destructor, for is it truly trivial?"
EDIT 3:
My second edit is just plain wrong and disinformation. Please read the comments by actual smart people for more info.
Consider the following case:
Base *Var = new Derived();
delete Var;
You need the virtual destructor, otherwise when you delete Var, the derived class' destructor will never be called.
If you delete a derived class object via a base class pointer in C++, the result is undefined behaviour. UB is something you really want to avoid, so you must give base classes a virtual destructor. To quote from the C++ Standard, section 5.3.5:
if the static type of the operand is
different from its dynamic type, the
static type shall be a base class of
the operand’s dynamic type and the
static type shall have a virtual
destructor or the behavior is
undefined.
You should use a virtual destructor if you expect people to try to delete objects of a derived class via pointers or references of the parent class. If this is the case, then without a virtual destructor, the derived class will never be properly destructed.
For example,
Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;
Without a virtual destructor in Base, Derived's destructor will never be called, and important stuff will therefore never happen.
Replying mostly to the edit:
Nobody can tell you what will happen because the result is "undefined behavior". When you delete a derived class through a pointer to a base that has no virtual destructor, the implementation is free to break down in any number of ways.
In general, a destructor should be either (1) public and virtual, or (2) protected and non-virtual.
Assuming you never expect anyone to delete a class instance via an interface pointer, a protected non-virtual destructor is 100% safe.
If someone tries to delete an interface pointer in case (2), they'll get a compile-time error.
No... virtual destructors are not auto generated. You have to declare them explicitely in your base class.
But you won't need to declare your destructors virtual for the child classes of Base. This is done by the compiler.
The compiler will also make sure that the destructors are called in reversed order of construction (from derived to base).
public class Base
{
//...
}
public class Derived
{
int i = 0;
//...
}
//...
Base* b = new Derived();
If you didn't have a virtual destructor
delete b;
would cause memory leaks (at least 4 bytes for the integer field), because it would destruct only Base and not Derived. The virtuality makes sure that the derived classes are destroyed, too. You won't have to declare a virtual constructor in Derived, this will be inferred by the compiler, if you declared a virtual destructor in Base.
Related
I know it is a good practice to declare virtual destructors for base classes in C++, but is it always important to declare virtual destructors even for abstract classes that function as interfaces? Please provide some reasons and examples why.
It's even more important for an interface. Any user of your class will probably hold a pointer to the interface, not a pointer to the concrete implementation. When they come to delete it, if the destructor is non-virtual, they will call the interface's destructor (or the compiler-provided default, if you didn't specify one), not the derived class's destructor. Instant memory leak.
For example
class Interface
{
virtual void doSomething() = 0;
};
class Derived : public Interface
{
Derived();
~Derived()
{
// Do some important cleanup...
}
};
void myFunc(void)
{
Interface* p = new Derived();
// The behaviour of the next line is undefined. It probably
// calls Interface::~Interface, not Derived::~Derived
delete p;
}
The answer to your question is often, but not always. If your abstract class forbids clients to call delete on a pointer to it (or if it says so in its documentation), you are free to not declare a virtual destructor.
You can forbid clients to call delete on a pointer to it by making its destructor protected. Working like this, it is perfectly safe and reasonable to omit a virtual destructor.
You will eventually end up with no virtual method table, and end up signalling your clients your intention on making it non-deleteable through a pointer to it, so you have indeed reason not to declare it virtual in those cases.
[See item 4 in this article: http://www.gotw.ca/publications/mill18.htm]
I decided to do some research and try to summarise your answers. The following questions will help you to decide what kind of destructor you need:
Is your class intended to be used as a base class?
No: Declare public non-virtual destructor to avoid v-pointer on each object of the class *.
Yes: Read next question.
Is your base class abstract? (i.e. any virtual pure methods?)
No: Try to make your base class abstract by redesigning your class hierarchy
Yes: Read next question.
Do you want to allow polymorphic deletion through a base pointer?
No: Declare protected virtual destructor to prevent the unwanted usage.
Yes: Declare public virtual destructor (no overhead in this case).
I hope this helps.
* It is important to note that there is no way in C++ to mark a class as final (i.e. non subclassable), so in the case that you decide to declare your destructor non-virtual and public, remember to explicitly warn your fellow programmers against deriving from your class.
References:
"S. Meyers. More Effective C++, Item 33 Addison-Wesley, 1996."
Herb Sutter, Virtuality, 2001
C++ Faq, 20.7, "When should my destructor be virtual?"
The answers to this question, of course.
Yes it is always important. Derived classes may allocate memory or hold reference to other resources that will need to be cleaned up when the object is destroyed. If you do not give your interfaces/abstract classes virtual destructors, then every time you delete a derived class instance via a base class handle your derived class' destructor will not be called.
Hence, you're opening up the potential for memory leaks
class IFoo
{
public:
virtual void DoFoo() = 0;
};
class Bar : public IFoo
{
char* dooby = NULL;
public:
virtual void DoFoo() { dooby = new char[10]; }
void ~Bar() { delete [] dooby; }
};
IFoo* baz = new Bar();
baz->DoFoo();
delete baz; // memory leak - dooby isn't deleted
It is not always required, but I find it to be good practice. What it does, is it allows a derived object to be safely deleted through a pointer of a base type.
So for example:
Base *p = new Derived;
// use p as you see fit
delete p;
is ill-formed if Base doesn't have a virtual destructor, because it will attempt to delete the object as if it were a Base *.
It's not only good practice. It is rule #1 for any class hierarchy.
The base most class of a hierarchy in C++ must have a virtual destructor
Now for the Why. Take the typical animal hierarchy. Virtual destructors go through virtual dispatch just as any other method call. Take the following example.
Animal* pAnimal = GetAnimal();
delete pAnimal;
Assume that Animal is an abstract class. The only way that C++ knows the proper destructor to call is via virtual method dispatch. If the destructor is not virtual then it will simply call Animal's destructor and not destroy any objects in derived classes.
The reason for making the destructor virtual in the base class is that it simply removes the choice from derived classes. Their destructor becomes virtual by default.
The answer is simple, you need it to be virtual otherwise the base class would not be a complete polymorphic class.
Base *ptr = new Derived();
delete ptr; // Here the call order of destructors: first Derived then Base.
You would prefer the above deletion, but if the base class's destructor is not virtual, only the base class's destructor will be called and all data in derived class will remain undeleted.
I came across a base class whose destructor is non-virtual, although the base class have 1 virtual function fv(). This base class also has many subclasses. Many of those subclasses define its own fv().
I don't know the details of how the base and subclasses are used in the program. I only know the program works fine even the destructor of base class should be virtual.
I want to change the destructor of base class from non-virtual to virtual. But I'm not sure of the consequences. So, what will happen? What more do I need to do to make sure the program works fine after I change it?
Follow up:
After I changed the base class's destructor from non-virtual to virtual, the program failed one test case.
The result confuses me. Because if the destructor of base class is not virtual, then the program won't use base class polymorphicaly. Because if not, it leads to undefined behavior. For example, Base *pb = new Sub.
So, I think if I change destructor from non-virtual to virtual, it shouldn't cause any more bugs.
The virtuality of the destructor will not break anything in the existing code unless there are other problems. It may even solve some (see below). However the class may not be designed as polymorphic so adding virtual to its destructor enables it as polymorphic-able which might not be desirable. Nevertheless you should be able to safely add virtuality to the destructor and it should cause no issues on itself.
Explanation
Polymorphism allows for this:
class A
{
public:
~A() {}
};
class B : public A
{
~B() {}
int i;
};
int main()
{
A *a = new B;
delete a;
}
You can take pointer to the object of type A of the class that is in fact of type B. This is useful for example for splitting interfaces (e.g. A) and implementations (e.g. B). However what will happen on delete a;?
Part of object a of type A is destroyed. But what about the part of type B? Plus that part has resources and they need to be freed. Well that is a memory leak right there. By calling delete a; you call the destructor of type A (because a is a pointer to type A), basically you call a->~a();. Destructor of type B is never called. How to solve this?
class A :
{
public:
virtual ~A() {}
};
By adding virtual dispatch to the A's destructor (note that by declaring base destructor virtual it automatically makes all derived classes' destructors virtual even when not declared as such). Then the call to delete a; will dispatch the call of the destructor into virtual table to find the correct destructor to use (in this case of type B). That destructor will call parent destructors as usual. Neat, right?
Possible Problems
As you can see by doing this you cannot break anything per se. However there might be different issues in your design. For example there might have been a bug that "relied" on the non-virtual call of the destructor that you exposed by making it virtual, consider:
int main()
{
B *b = new B;
A *a = b;
delete a;
b->i = 10; //might work without virtual destructor, also undefined behvaiour
}
Basically object slicing, but since you did not have virtual destructor before then B part of the created object was not destroyed hence the assignment to i might work. If you made the destructor virtual then it does not exist and it will likely crash or do whatever (undefined behaviour).
Things like these might happen and in complicated code it may be hard to find. But if your destructor causes crashes after you made it virtual you likely have a bug like this somewhere in there and you had it there to begin with because as I said just making the destructor virtual cannot break anything on its own.
Have a look here,
struct Component {
int* data;
Component() { data = new int[100]; std::cout << "data allocated\n"; }
~Component() { delete[] data; std::cout << "data deleted\n"; }
};
struct Base {
virtual void f() {}
};
struct Derived : Base {
Component c;
void f() override {}
};
int main()
{
Base* b = new Derived;
delete b;
}
The output:
data allocated
but not deleted.
Conclusion
Whenever a class hierarchy has state, on the purely technical level, you want a virtual destructor all the way from the top.
It is possible that once you added that virtual destructor to your class, you triggered untested destruction logic. The sane choice here is to keep the virtual destructor you've added, and fix the logic. Otherwise, you're going to have resource and/or memory leaks in your process.
Technical Details
What's happening in the example is that, while Base has a vtable, its destructor itself isn't virtual, and that means that whenever Base::~Base() is called, it doesn't go through a vptr. In other words, it simply calls Base::Base(), and that's it.
In the main() function, a new Derived object is allocated and assigned to a variable of type Base*. When the next delete statement runs, it actually first attempts to call the destructor of the directly passed type, which is simply Base*, and then it frees the memory occupied by that object. Now, since the compiler sees that Base::~Base() isn't virtual, it doesn't attempt to go through the vptr of the object d. This means that Derived::~Derived() is never called by anyone. But since Derived::~Derived() is where the compiler generated the destruction of the Component Derived::c, that component is never destroyed either. Therefore, we never see data deleted printed.
If Base::~Base() were virtual, what would happen is that the delete d statement would go through the vptr of the object d, calling the destructor, Derived::~Derived(). That destructor, by definition, would first call Base::~Base() (this is auto-generated by the compiler), and then destroy its internal state, that is, Component c. Thus, the entire destruction process would have completed as expected.
It depends on what your code is doing, obviously.
In general terms, making the destructor of the base class virtual is only necessary if you have a usage like
Base *base = new SomeDerived;
// whatever
delete base;
Having a non-virtual destructor in Base causes the above to exhibit undefined behaviour. Making the destructor virtual eliminates the undefined behaviour.
However, if you do something like
{ // start of some block scope
Derived derived;
// whatever
}
then it is not necessary for the destructor to be virtual, since the behaviour is well defined (the destructors of Derived and its bases are invoked in reverse order of their constructors).
If changing the destructor from non-virtual to virtual causes a test case to fail, then you need to examine the test case to understand why. One possibility is that the test case relies on on some specific incantation of undefined behaviour - which means the test case is flawed, and may not succeed in different circumstances (e.g. building the program with a different compiler). Without seeing the test case (or an MCVE that is representative of it), however, I'd hesitate to claim it DOES rely on undefined behaviour
It may break some tests if someone who derived from a base class changed the ownership policy of class's resources:
struct A
{
int * data; // does not take ownership of data
A(int* d) : data(d) {}
~A() { }
};
struct B : public A // takes ownership of data
{
B(int * d) : A (d) {}
~B() { delete data; }
};
And usage:
int * t = new int(8);
{
A* a = new B(t);
delete a;
}
cout << *t << endl;
Here making the A's destructor virtual will cause UB. I don't think that such usage can be called a good practice, though.
You may "safely" add virtual to the destructor.
You may fix Undefined Behavior (UB) if equivalent of delete base is called, and then call the right destructors. If the subclass destructor is buggy, then you change UB by an other bug.
One thing that could change is the class's layout type. Adding a virtual destructor can change a class from being a standard-layout type to a non-standard-layout class. So anything were you rely on the class being a POD or standard-layout type, e.g.
memcpy or memmve classes around
pass to C functions
will be UB.
I know of exactly one case where a type is
used as a base class
has virtual functions
the destructor is not virtual
making the destructor virtual breaks things
and that is when the object conforms to an external ABI. All COM interfaces on Windows meet all four criteria. This isn't undefined behavior, but non-portable implementation-specific guarantees concerning the virtual dispatch machinery.
Regardless of your OS, it boils down to "The One-Definition Rule". You can't modify a type unless you recompile every piece of code using it against the new definition.
I know it is a good practice to declare virtual destructors for base classes in C++, but is it always important to declare virtual destructors even for abstract classes that function as interfaces? Please provide some reasons and examples why.
It's even more important for an interface. Any user of your class will probably hold a pointer to the interface, not a pointer to the concrete implementation. When they come to delete it, if the destructor is non-virtual, they will call the interface's destructor (or the compiler-provided default, if you didn't specify one), not the derived class's destructor. Instant memory leak.
For example
class Interface
{
virtual void doSomething() = 0;
};
class Derived : public Interface
{
Derived();
~Derived()
{
// Do some important cleanup...
}
};
void myFunc(void)
{
Interface* p = new Derived();
// The behaviour of the next line is undefined. It probably
// calls Interface::~Interface, not Derived::~Derived
delete p;
}
The answer to your question is often, but not always. If your abstract class forbids clients to call delete on a pointer to it (or if it says so in its documentation), you are free to not declare a virtual destructor.
You can forbid clients to call delete on a pointer to it by making its destructor protected. Working like this, it is perfectly safe and reasonable to omit a virtual destructor.
You will eventually end up with no virtual method table, and end up signalling your clients your intention on making it non-deleteable through a pointer to it, so you have indeed reason not to declare it virtual in those cases.
[See item 4 in this article: http://www.gotw.ca/publications/mill18.htm]
I decided to do some research and try to summarise your answers. The following questions will help you to decide what kind of destructor you need:
Is your class intended to be used as a base class?
No: Declare public non-virtual destructor to avoid v-pointer on each object of the class *.
Yes: Read next question.
Is your base class abstract? (i.e. any virtual pure methods?)
No: Try to make your base class abstract by redesigning your class hierarchy
Yes: Read next question.
Do you want to allow polymorphic deletion through a base pointer?
No: Declare protected virtual destructor to prevent the unwanted usage.
Yes: Declare public virtual destructor (no overhead in this case).
I hope this helps.
* It is important to note that there is no way in C++ to mark a class as final (i.e. non subclassable), so in the case that you decide to declare your destructor non-virtual and public, remember to explicitly warn your fellow programmers against deriving from your class.
References:
"S. Meyers. More Effective C++, Item 33 Addison-Wesley, 1996."
Herb Sutter, Virtuality, 2001
C++ Faq, 20.7, "When should my destructor be virtual?"
The answers to this question, of course.
Yes it is always important. Derived classes may allocate memory or hold reference to other resources that will need to be cleaned up when the object is destroyed. If you do not give your interfaces/abstract classes virtual destructors, then every time you delete a derived class instance via a base class handle your derived class' destructor will not be called.
Hence, you're opening up the potential for memory leaks
class IFoo
{
public:
virtual void DoFoo() = 0;
};
class Bar : public IFoo
{
char* dooby = NULL;
public:
virtual void DoFoo() { dooby = new char[10]; }
void ~Bar() { delete [] dooby; }
};
IFoo* baz = new Bar();
baz->DoFoo();
delete baz; // memory leak - dooby isn't deleted
It is not always required, but I find it to be good practice. What it does, is it allows a derived object to be safely deleted through a pointer of a base type.
So for example:
Base *p = new Derived;
// use p as you see fit
delete p;
is ill-formed if Base doesn't have a virtual destructor, because it will attempt to delete the object as if it were a Base *.
It's not only good practice. It is rule #1 for any class hierarchy.
The base most class of a hierarchy in C++ must have a virtual destructor
Now for the Why. Take the typical animal hierarchy. Virtual destructors go through virtual dispatch just as any other method call. Take the following example.
Animal* pAnimal = GetAnimal();
delete pAnimal;
Assume that Animal is an abstract class. The only way that C++ knows the proper destructor to call is via virtual method dispatch. If the destructor is not virtual then it will simply call Animal's destructor and not destroy any objects in derived classes.
The reason for making the destructor virtual in the base class is that it simply removes the choice from derived classes. Their destructor becomes virtual by default.
The answer is simple, you need it to be virtual otherwise the base class would not be a complete polymorphic class.
Base *ptr = new Derived();
delete ptr; // Here the call order of destructors: first Derived then Base.
You would prefer the above deletion, but if the base class's destructor is not virtual, only the base class's destructor will be called and all data in derived class will remain undeleted.
in C++: Why should the destructor of base classes be virtual?
The better question is when and why. Your question indicates that you think all base classes should have virtual destructors, which is not quite true.
It would make it impossible to apply the empty base class optimization, and could multiply the size of classes up to 16 times than what it would be without virtual on common platforms.
A virtual destructor is needed when you delete an object whose dynamic type is DerivedClass by a pointer that has type BaseClass*. The virtual makes the compiler associate information in the object making it able to execute the derived class destructor. Missing the virtual in such case causes undefined behavior.
If you don't need this, and your class is only used as a base class, it's best to make the destructor protected, thus preventing that users accidentally delete in the described way.
You want them to be virtual so that all subclass destructors are automatically called when the object is destroyed, even if it is destroyed through a pointer to the base class. In the following code:
class base {
public:
virtual ~base() { }
};
class derived : public base {
public:
~derived() { } // Inherits the virtual designation
};
int main(void)
{
base *b = new derived;
delete b;
}
The derived destructor will only be called if the base destructor is virtual.
As Magnus indicates, you don't have to do this if you aren't taking advantage of polymorphism. However, I try to develop the habit of declaring all my destructors virtual. It protects me against the case where I should have declared them virtual but forget to do so. As Johannes indicates, this habit can impose a small space and performance penalty when the virtual designation is not needed.
They dont have to be virtual unless you are using polymorphism. If you do use polymorphism they need to be virtual so that the destructors of inherited classes are guaranteed to be called, so inherited classes can do their clean up.
For situations like this:
class A
{
virtual ~A();
};
class B:A
{
~B();
};
A *a = new B(); //legal, since it's a downcast
delete a; //Unless the destructor is virtual, ~A() is called here instead of ~B().
It should be virtual to ensure that the destructor of the inherited classes are the ones actually getting called at runtime instead of the base class destructor being called.
I know it is a good practice to declare virtual destructors for base classes in C++, but is it always important to declare virtual destructors even for abstract classes that function as interfaces? Please provide some reasons and examples why.
It's even more important for an interface. Any user of your class will probably hold a pointer to the interface, not a pointer to the concrete implementation. When they come to delete it, if the destructor is non-virtual, they will call the interface's destructor (or the compiler-provided default, if you didn't specify one), not the derived class's destructor. Instant memory leak.
For example
class Interface
{
virtual void doSomething() = 0;
};
class Derived : public Interface
{
Derived();
~Derived()
{
// Do some important cleanup...
}
};
void myFunc(void)
{
Interface* p = new Derived();
// The behaviour of the next line is undefined. It probably
// calls Interface::~Interface, not Derived::~Derived
delete p;
}
The answer to your question is often, but not always. If your abstract class forbids clients to call delete on a pointer to it (or if it says so in its documentation), you are free to not declare a virtual destructor.
You can forbid clients to call delete on a pointer to it by making its destructor protected. Working like this, it is perfectly safe and reasonable to omit a virtual destructor.
You will eventually end up with no virtual method table, and end up signalling your clients your intention on making it non-deleteable through a pointer to it, so you have indeed reason not to declare it virtual in those cases.
[See item 4 in this article: http://www.gotw.ca/publications/mill18.htm]
I decided to do some research and try to summarise your answers. The following questions will help you to decide what kind of destructor you need:
Is your class intended to be used as a base class?
No: Declare public non-virtual destructor to avoid v-pointer on each object of the class *.
Yes: Read next question.
Is your base class abstract? (i.e. any virtual pure methods?)
No: Try to make your base class abstract by redesigning your class hierarchy
Yes: Read next question.
Do you want to allow polymorphic deletion through a base pointer?
No: Declare protected virtual destructor to prevent the unwanted usage.
Yes: Declare public virtual destructor (no overhead in this case).
I hope this helps.
* It is important to note that there is no way in C++ to mark a class as final (i.e. non subclassable), so in the case that you decide to declare your destructor non-virtual and public, remember to explicitly warn your fellow programmers against deriving from your class.
References:
"S. Meyers. More Effective C++, Item 33 Addison-Wesley, 1996."
Herb Sutter, Virtuality, 2001
C++ Faq, 20.7, "When should my destructor be virtual?"
The answers to this question, of course.
Yes it is always important. Derived classes may allocate memory or hold reference to other resources that will need to be cleaned up when the object is destroyed. If you do not give your interfaces/abstract classes virtual destructors, then every time you delete a derived class instance via a base class handle your derived class' destructor will not be called.
Hence, you're opening up the potential for memory leaks
class IFoo
{
public:
virtual void DoFoo() = 0;
};
class Bar : public IFoo
{
char* dooby = NULL;
public:
virtual void DoFoo() { dooby = new char[10]; }
void ~Bar() { delete [] dooby; }
};
IFoo* baz = new Bar();
baz->DoFoo();
delete baz; // memory leak - dooby isn't deleted
It is not always required, but I find it to be good practice. What it does, is it allows a derived object to be safely deleted through a pointer of a base type.
So for example:
Base *p = new Derived;
// use p as you see fit
delete p;
is ill-formed if Base doesn't have a virtual destructor, because it will attempt to delete the object as if it were a Base *.
It's not only good practice. It is rule #1 for any class hierarchy.
The base most class of a hierarchy in C++ must have a virtual destructor
Now for the Why. Take the typical animal hierarchy. Virtual destructors go through virtual dispatch just as any other method call. Take the following example.
Animal* pAnimal = GetAnimal();
delete pAnimal;
Assume that Animal is an abstract class. The only way that C++ knows the proper destructor to call is via virtual method dispatch. If the destructor is not virtual then it will simply call Animal's destructor and not destroy any objects in derived classes.
The reason for making the destructor virtual in the base class is that it simply removes the choice from derived classes. Their destructor becomes virtual by default.
The answer is simple, you need it to be virtual otherwise the base class would not be a complete polymorphic class.
Base *ptr = new Derived();
delete ptr; // Here the call order of destructors: first Derived then Base.
You would prefer the above deletion, but if the base class's destructor is not virtual, only the base class's destructor will be called and all data in derived class will remain undeleted.