I've seen this asked before, but not clearly or in the same situation as I have encountered.
I have an abstract base class. It has a protected constructor and a destructor. It is inherited by several complete types which also have public constructors and destructors. I'm having the issue where deleting the object isn't calling the child destructors if the object is referenced by the base type.
class Tree
{
protected:
Tree(){ }
public:
~Tree(){ }
};
class OakTree : public Tree
{
public:
OakTree(){ }
~OakTree(){ }
};
vector<Tree*> Trees; // Store objects using the base type
Trees.push_back(new OakTree()); // Create derived object
delete Trees[0]; // OakTree desctructor does not get called
How can I get the OakTree destructor called? I've tried marking all of the destructors to virtual but that didn't work. The base class destructor cannot be abstract (this would solve the calling problem but not the delete problem).
Make your base-class destructor virtual.
class Tree
{
protected:
Tree(){ }
public:
virtual ~Tree(){ }
}
Otherwise, undefined behavior will result if you try to delete through a base-class pointer. It's a bit dated, but Scott Meyers expressed this colorfully in Effective C++, 2nd ed:
The C++ language standard is unusually clear on this topic: when you try to delete a derived class object through a base class pointer and the base class has a nonvirtual destructor (as EnemyTarget does), the results are undefined. This means compilers may generate code to do whatever they like: reformat your disk, send suggestive mail to your boss, fax source code to your competitors, whatever. (What often happens at runtime is that the derived class's destrutcor is never called. ...)
It's because your base class destructor is not declared virtual.
class Tree
{
protected:
Tree(){ }
public:
virtual ~Tree(){ }
}
If you are going to use polymorphism you have to have a virtual destructor in your base class.
The problem is that when you call delete on a Tree * nobody really knows what kind of tree it is, and by having a virtual destructor the compiler generates a call through the pointer that points to the table for functions for that particular object instance, and you get the destructor for whatever that type might be.
Otherwise the standard says it is undefined behavior, but what seems to happen most of the times is the compiler generates a call to the destructor of whatever type your polymorphic pointer or reference is, in your case, that is the base class.
I wonder why nobody is actually asking what the author is trying to achieve with the code?
While, yes, having a virtual destructor in the base class will help you to get your destructor called, what you're still left with is undefined behavior.
What do you expect after the line delete Trees[0];?
Or, rather, what are you trying to achieve with that line?
If you're trying to erase the item from the vector, you might want:
Trees.erase(Trees.begin());
But then, you're left with the memory leak if you forget the delete line.
Hence, don't use plain pointers in your vector. Consider:
std::vector< std::shared_ptr<Tree> > Trees;
Trees.push_back( std::make_shared<OakTree>() );
Trees.erase(Trees.begin());
Runnable #Ideone
Related
This question already has answers here:
When to use virtual destructors?
(20 answers)
Closed 3 years ago.
Based on what I found here and on other links on stackoverflow, we should always define a virtual destructor in the base class if we plan to use it polymorphically. I want to know if there is an exception to this rule.
I have seen production code that does not define virtual destructor for the pure abstract base classes and in one of cppcon 2014 video Accept no visitor, around 10:06 the BoolExp struct defined is a pure abstract class and has no virtual destructor.
So for a pure abstract class defined like this
class Base {
public:
virtual foo() = 0;
virtual bar() = 0;
}
My question is it absolutely must that we define a virtual destructor for "Base" class, even though it does have any data members? Are there any exceptions to the virtual destructor rule?
Thanks in advance.
Best,
RG
My question is it absolutely must that we define a virtual destructor for "Base" class, even though it does have any data members?
It depends. If you have a case like
base * foo = new child(stuff);
// doing stuff
delete foo;
then you absolutely must have a virtual destructor. Without it you'll never destroy the child part.
If you have a case like
child * foo = new child(stuff);
// doing stuff
delete foo;
Then you do not need a virtual destructor, as child's will be called.
So the rule is if you delete polymorphically, you need a polymorphic (virtual) destructor, if not, then you don't
The exception to the rule is if you never delete an object through a pointer to the base class. In that case the base class destructor does not need to be virtual.
But if you ever delete an object via a base class pointer, then the base class destructor must be virtual or your program has Undefined Behaviour.
My question is it absolutely must that we define a virtual destructor for "Base" class, even though it does have any data members?
Stricktly speaking, No.
However, whether the base class has any member variables is not relevant. If the destructor gets called using a pointer to the base class, your code has undefined behavior regardless of whether the base class has any member variables or not.
Are there any exceptions to the virtual destructor rule?
If you are able to manage lifetimes of derived classes in such a way that the call to delete the objects is done via derived class pointers, you don't invoke undefined behavior and your code will be well behaved, assuming everything else is in your code base is in good order.
we should always define a virtual destructor in the base class if we plan to use it polymorphically.
You should always define a virtual destructor in a base classs if we plan to delete it polymorphically through that base class.
Now, one problem is that "I don't intend to" isn't safe; you should make it impossible.
Make the destructor virtual (and empty), or make it protected (and empty). A protected destructor makes polymorphic deletion unlikely (it can be bypassed, but only through pretty insane means).
Barring that, you have to be careful. This is one of the reasons why inheriting from (say) std vector is a thing to be wary of.
is it absolutely must that we define a virtual destructor for "Base" class, even though it does have any data members? Are there any exceptions to the virtual destructor rule?
It is not a must. It's a good habit that can prevent bugs.
If you decide to create a base class that doesn't have a virtual destructor, it is the responsibility of you, the developer, to always ensure that derived objects are deleted as the correct type or as a base type that does have a virtual destructor.
Deleting a derived class object using a pointer to a base class that has a non-virtual destructor results in undefined behavior.
Otherwise you are ok to not to have virtual destructor.
I would like to make an important (at least, in my view) practical amendment to correct answers describing the deletion through base object.
In particular, the destructors are called non-virtually if object life-time is managed through std::shared_ptr<Base> allocated via
std::shared_ptr<Base> sptr = std::make_shared<Derived>(args);
Looking at the C++ language standard, is there any way to call only derived class destructor, without calling destructor of the base class?
So, for classes
class Base { public: virtual ~Base() {} };
class Derived : public Base { public: ~Derived();};
if would be possible to write code like
Base *basePtr = new Derived();
//do something with basePtr
// Now somehow destroy Derived while keeping Base - call ~Derived() only,
// line below however will call both ~Derived() and ~Base() - how it can be done?
dynamic_cast<Derived*>(basePtr)->~Derived();
So, after execution of the code above basePtr will point to Base object only, like if it was created by
Base *basePtr = new Base();
plus any modifications to the Base object caused by manipulating basePtr between calling new Derived() and destroying Derived class?
Or, is this forbidden and it is impossible to do?
No, this is not possible. The standard demands that the destruction of a Derived object destroys the whole object, including the Base subobject. Anything else would not be a destruction according to C++'s understanding of object lifetime.
Depending on what you want to achieve, consider to copy the Base out of the derived first
std::unique_ptr<Base> basePtr(new Derived());
//do something with basePtr
basePtr.swap(std::unique_ptr<Base> (new Base(*basePtr))); //splice the Base part out of the derived object
//basePtr now points to the spliced Base object.
Another approach would be to hold the additional members that derived has in a boost::optional (or just a pimpl) and reset that to get a "stripped" Derived object that still has its Base class part. This will however not affect virtual function dispatch.
As you have formulated the question, it is not possible to achieve what you are asking for. Unless you have a memory leak, the only case when explicitly calling a destructor does not lead to undefined behavior is if the object was created by placement new. Even then, calling the destructor will automatically call the destructor of every member and base class.
This is as it should be. Otherwise it would be very difficult to write a correct container class or memory manager.
The standard says that the lifetime of an object ends as soon as it enters the destructor. It does not become a base class object. It ceases to be an object, entirely. Also, if this was not the case, what would be the status of a class deriving from multiple bases after such a trick?
Ultimately, the "need" for such a functionality is a sign of bad design. I would guess your use case more likely requires composition. See if you can't solve it with a new class which holds one instance of what is currently the base class and one optional, replaceable component of (a smart pointer to) some dummy class which serves as an interface to and the new common base of your current derived classes. That way you can remove (and destruct) those sub objects without touching the base.
Destructors are called automatically in the reverse order of construction. I do not believe there is any way around this.
This is not possible to do unless your derived class has nothing to do with your base class.
Destructors are called in automatic way.Explicitly call destructor may result in undefined behavior.
This question looks like the discussion in Virtual destructor: is it required when not dynamically allocated memory?
In an exam question, I have been asked:
- What should any base class that maintain pointers to dynamically allocated memory define?
I answered:
- A copy constructor and an assignment operator (to make sure NOT only pointers are copied... c.f. deep copy), and a destructor (to free allocated memory)
They said this is not correct because this base class should also define a virtual destructor instead of the plain destructor. Why?
If your class is intended to be used polymorphically, you'll likely have pointers to the base class that point to derived objects.
Deleting a derived object through a pointer to a base class with no virtual destructor causes undefined behavior. That's probably her reasoning.
5.3.5
3) In the first alternative (delete object ), 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. [...]
Your base class needs a virtual destructor if objects of derived classes are intended to be destroyed via a base-class pointer, like so
Base *pointer_to_base_class = new Derived;
delete pointer_to_base_class;
From your question, it is unclear whether this is the case. Perhaps another part of the question (or a previous question) made clear that such polymorphic destruction was intended. Or, perhaps you were taught during the class to always anticipate such use as a best practice.
They are not 100% correct. Virtual destructor is a must if
class hierarchy used with dynamic polymorphism AND
derived objects are destroyed via pointer to base.
Otherwise non-virtual destructor is OK. But in most cases even if only #1 is intended it's a good style to make destructor virtual regardless of #2.
Within the standard, most inheritance hierarchies have a virtual destructor at their base; however, sub_match is defined to public inherit from std::pair<BidirectionalIterator, BidirectionalIterator> and as such it could own dynamically allocated memory. In a related area, match_results is not required to but usually implemented to public inherit from std::vector<...> which definitely allocates memory.
Your examiner is not entirely incorrect, but the focus on dynamically allocated memory is a red herring and betrays a worrying ignorance of the standard; while in most implementations deleting a derived type by a pointer to base type without virtual destructor will result in destructing a sliced object, per the standard it is undefined behaviour.
Adding to the other answers: You could also envisage a situation where you do want a common base class, but you don't have any actual interface functions for it. But if you want RTTI and dynamic cast support, you need a virtual function in your class. A destructor can be just that function.
For example, imagine you're a recovering Java programmer and insist that everything is an Object. You might start your first C++ program like so:
class Object
{
public:
virtual ~Object() { }
};
Now Object can indeed serve as the ultimate polymorphic base class of each of your classes.
If you also think that Object should be abstract, you can even make the destructor pure-virtual:
class Object { public: virtual ~Object() = 0; }; Object::~Object() { }
To follow up with all good answers here this is good practice to declare a virtual destructor to ensure a proper clean-up when a class is supposed to be subclassed to form a hierarchy and you want to delete the derived object through a pointer to it. The C++ standard is clear on this:
when you want to delete a derived class object through a base class
pointer and the destructor of the base class is not virtual and the
result is undefined
By undefined behavior you could think of memory leaks for example if your derived class allocate some dynamic memories and you try to delete it later on through this base class. Your teacher was probably thinking of this scenario.
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.