Consider these two classes in C++11:
class A
{
ArbitraryClass someInstance;
};
class B : public A
{
};
And consider I use B as such:
B *foo = new B;
delete foo;
As I understand, the implicit destructor of A will not be called here.
Is someInstance still destroyed under these circumstances, because it becomes "associated" as a member of B? Or do I need to declare a virtual destructor on A to automatically trigger the member's destruction?
You need a virtual destructor in a delete expression's statically known class (in your case B) if that class is different from the most derived class of the object (in your case also B). In your case those classes are the same, so you don't need a virtual destructor: everything's destroyed properly. But if you had made the pointer type A*, then you'd need a virtual destructor in A to avoid Undefined Behavior (nasal daemons and such).
How do I ensure ...
Mostly by doing nothing.
As I understand, the implicit destructor of A will not be called here.
Wrong.
Is someInstance still destroyed under these circumstances
Yes.
because it becomes "associated" as a member of B?
Because it is a member of A, and A is destroyed.
Or do I need to declare a virtual destructor on A to automatically trigger the member's destruction?
Not in the case of the code you posted, but if (as is likely) you will be using polymorphism by deleting pointers to A that could be B or other subclasses of A you should give A a virtual destructor.
Related
Let's say that I use an external library full of various classes. When I can safely inherit from one of those classes? I know that the base class must have a virtual destructor. Is there something else I should check before using the class as the base class? Can I be sure that it is safe only if the docs state so?
If the documentation states that it is safe to derive a type, follow the documentation. If, for some reason, it behaves in a way that goes against the documentation, then this is a problem with the library and is a bug for the authors to fix or offer workarounds for, because they are not committing to the API that they guarantee in the documentation.
Any type that is not final can be derived "safely"; what matters more is how this type is handled and destroyed. If you inherit from a type that has no virtual destructor, this doesn't inherently break anything; it just prevents having the derived type's destructor get called if you destroy that from a handle to the base.
If you only ever destroy the type from a handle to the derived type, (e.g. you either hold it concretely, or never destroy it from a handle to the base), then this has no consequence.
To better explain my point, imagine the following hierarchy:
class Base {
public:
// No virtual destructor
...
};
class Derived : public Base {
public:
...
private:
std::string m_something; // some leakable object
};
The derivation of Derived from Base is completely safe to do. What matters is how it gets destroyed for whether there will be a problem. For this there are two different cases to consider: Automatic and Dynamic cases.
Automatic Objects
Automatic types ("by-value" types) are safe, regardless of whether they have static lifetime or not
auto d = Derived{ ... };
static auto sd = Derived{ ... };
At the end of their lifetime, the destructor Derived::~Derived will be called, since the type is concretely known
Dynamic Objects
Dynamic objects don't get destroyed on their own. Their resources need to be cleaned up eventually, either automatically with RAII in a smart pointer, by someone calling delete, or by someone explicitly calling ~T() and freeing the memory.
These are still safe if they are destroyed by a handle to the derived type, but will not be if they are destroyed by a handle to the base.
auto* d1 = new Derived{ ... };
auto* d2 = new Derived{ ... };
// Deleting as a pointer to Base; ~Derived won't be called because ~Base is virtual
// This would be a memory leak
delete static_cast<Base*>(d1); // bad
// Deleting as a pointer to Derived -- ~Derived will be called, this is fine
delete d2; // good
In terms of Smart Pointer types:
Shared Pointer
shared_ptr types are safe, since they always destroy objects from the concrete type -- even if they get aliased to a base class.
void accept_base(std::shared_ptr<Base> b);
auto d = std::make_shared<Derived>(...);
// still safe
accept_base(std::move(d));
Unique Pointer
unique_ptr types are not safe by default due to the default deleter deleting based on the T type of unique_ptr.
For example:
auto d = std::make_unique<Derived>(...);
auto b = std::unique_ptr<Base>{std::move(d)};
// b will be destroyed at end of scope by calling ~Base, which is not virtual!
Even with all of this said: If you're using a library that explicitly states that you are meant to derive some XYZ class, then you should still assume that this is how the class should be used. At that point, if something undesirable occurs, it will be up to the library maintainer to ensure that their code performs as documented, since it's part of their expressly stated API.
If you intend to call methods from a Base class reference or pointer, you should also check if they are declared virtual.
Apart from that I would look into the documentation of the class and whether it is declared final
You actually do not need a virtual destructor for it to be safe to inherit from a class. You only need a virtual destructor, if you want to use (and thereby destroy) the class from a pointer to its base class.
It all depends on how you intend to use the derived class.
For instance, if you just want to make a class that inherits from the given class, but you do not intend to use it in a base class pointer or reference.
Base baseObj;
Derived derivedObject; // This does not create any problems
If you want to use it from a pointer or reference (this also applies to smart pointers of course) to the base class like this:
Base* basePtr = new Base();
Base* basePtrToDerived = new Derived();
Derived* derivedPtrToDerived = new Derived();
// Do stuff here
delete basePtr;
delete basePtrToDerived; // if Base has no virtual destructor, only the destructor of Base is called
delete derivedPtrToDerived; // This will always call the destructor of Derived
you need a virtual destructor.
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.
In the code below, b is a base-class pointer. However, when I invoke the destructor (either explicitly or implicitly via delete), the derived class destructor is invoked first. I don't understand how this works. There could be any number of derived classes, each with their own destructors. How can the compiler know which derived class destructor to invoke from the base destructor?
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base {
public:
~Derived() { cout << "Derived destructor" << endl; }
};
int main(int argc, char * argv[]) {
Base * b = new Derived();
b->~Base(); // delete b; has the same result
}
dynamic binding, the compiler doesn't decide, the runtime does because the destructor is virtual. C++ destruction calls the destructor on the current class and implicitly calls the parent class until it hits the base class.
The call to virtual destructor works the same as a call to any other virtual function, as a result of virtual dispatch via virtual table. Apart from this,
b->~Base(); // delete b; "has the same result"
this is not true, because delete also frees the memory, which you haven't done here. delete b calls a destructor for *b and deallocates raw memory to operating system. You have only destroyed the building but haven't given ground back.
This is done the same way as virtual functions. Its called dynamic binding. When non virtual member functions are resolved statically means at compile-time, virtual members are resolved dynamically means during run time. Compiler maintains a vtable for this. If the object has one or more virtual functions, the compiler puts a hidden pointer in the object called a "virtual-pointer" or "v-pointer." This v-pointer points to a global table called the "virtual-table" or "v-table.". Read more in details from here.
It doesn't. It happens the other way around. Normal virtual function despatching calls the derived destructor, and the derived destructor calls the base destructor.
Note: My first answer was so off-base that I deleted it. It was so far off-base that someone should have down voted my response. This is another try.
In the opening post, master_latch asked:
How can the compiler know which derived class destructor to invoke from the base destructor?
How this happens is implementation specific.
Why this has to happen is "because the standard says so." Here's what the standard says:
C++11 12.4 paragraph 5:
After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant members, the destructors for X’s direct base classes and, if X is the type of the most derived class, its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor. A return statement in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called. Destructors for elements of an array are called in reverse order of their construction.
C++11 12.4 paragraph 10:
In an explicit destructor call, the destructor name appears as a ~ followed by a type-name or decltype-specifier that denotes the destructor’s class type. The invocation of a destructor is subject to the usual rules for member functions, ...
The example code in C++11 12.4 paragraph 10 indicates the intent of the above:
struct B {
virtual ~B() { }
};
struct D : B {
~D() { }
};
D D_object;
B* B_ptr = &D_object;
void f() {
D_object.B::~B(); // calls B’s destructor
B_ptr->~B(); // calls D’s destructor
...
}
master_latch, your example of using b->~Base(); is identical to the second call in the example code. Think of b->~Base(); as if it meant b->__destruct_me(). It is in a sense no different than a call to any other virtual function.
A compliant implementation has to do this because "because the standard says so." How an implementation does it? The standard doesn't say. (That's good requirementese, by the way. Say what has to be done, but don't say how to do it.)
Most implementations (every implementation I have poked into) do this by generating multiple functions for a destructor. One function implements the body of the destructor as specified by the programmer. A wrapper destructor executes this body of the destructor function, then destroys non-static data members in reverse order of construction, and then invokes parent class destructors. That classes can virtually inherit from some parent class adds another twist. This means that a third destructor function for a given class might be needed.
So how does an implementation know that b->~Base() should call the wrapper destructor for class Derived? Dynamically casting a pointer to a polymorphic class to a void* pointer yields a pointer to the most derived object.
C++11 5.2.7 paragraph 7:
If T is “pointer to cv void,” then the result is a pointer to the most derived object pointed to by v. Otherwise, a run-time check is applied to see if the object pointed or referred to by v can be converted to the type pointed or referred to by T.
In other words, dynamically casting a polymorphic pointer to void* yields a pointer to the object as it was declared or allocated. The virtual table (not a part of the standard) dictates how to find the destructor. The implementation ensures that the pointer to the virtual table can be determined from a void* pointer to the most derived object. This is what lets the implementation know which destructor to call. From that point on, the pointer to that most derived object is no longer a void* pointer.
If I have a base class and a derived class, and I delcare the destructor in the parent virtual, but instantiate an object of type subclass, when destroyed it will invoke the parent destructor right(since virtual)? If I also declare a destructor in the derived class, will it call both destructors (base and derived). Thanks in advance :-).
The second part to my question is regarding the first. Why does the base class destructor need to be declared virtual. Don't constrcutors cycle up the hiearchy. They don't share the same name, so where's the need for it? Shouldn't it work the same for destrucotrs, or by default is only one called? Also does through late binding is it able to detect all the classes and object is made of?
EDIT: My question is not just about virtual destructors, but why does it need to be declared virtual, since they should all be called by default.
Yes, parent destructors will be called automatically.
The destructor should be virtualised so a derived instance can be destroyed properly by code that thinks it has a reference to a base class instance.
In very limited circumstances, it is OK not to virtualise, if you really need to save a few cycles on the vtable lookup.
The need for virtual destructors is because of polymorphism. If you have something like the following:
class A { ... };
class B : public A { ... };
void destroy_class(A* input)
{
delete input;
}
int main()
{
B* class_ptr = new B();
destroy_class(class_ptr); //you want the right destructor called
return 0;
}
While a bit of a contrived example, when you delete the passed-in pointer for the destroy_class() function, you want the correct destructor to get called. If the destructor for class A was not declared virtual, then only the destructor for class A would get called, not the destructor for class B or any other derived type of class A.
Stuff like this is very often a fact-of-life with non-template polymorphic data-structures, etc. where a single deletion function may have to delete pointers of some base-class type that actually points to an object of a derived type.
rubixibuc,
Yeah the subclasses destructor is invoked first, then it's superclass... then it's superclass, and so on until we get to Object's destructor.
More here: http://www.devx.com/tips/Tip/13059 ... it's worth the read... only a screen-full, but it's an INFORMATIVE screen-full.
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.