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.
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.
In terms of inheritance, I understand that it's advised for your classes' destructors to be virtual, so the base class's destructor gets called correctly in addition to any derived destructors. However, I'm wondering if there are any stack-related issues that relate to derived objects in the following scenario.
Let's suppose we have a Base class that doesn't have a destructor (for whatever reason):
class Base{};
and a Derived class that DOES have a destructor:
class Derived : public Base
{
~Derived(){}
};
And in the main...:
int main()
{
Derived a;
return 0;
}
Do I run into any issues from the Base class not having a destructor? My initial guess is that the compiler will just generate a default destructor for the Base class. Again, my question is mostly related to the stack rather than dynamic memory: is there any weirdo scenario I need to look out for in order to avoid a Derived destructor being called and the Base destructor is not?
The rule you're thinking of is that if you delete an object of a derived type through a pointer to one of its base types and that base type does not have a virtual destructor the behavior is undefined. The code here doesn't delete anything, so the rule does not apply.
To ensure safety, it is sufficient that every destructor (implicit or explicit) be at least one of:
virtual (for base classes if you need to delete subclass instances through base class pointers)
protected (to ensure that it is impossible to attempt to delete through a base class pointer)
final (actually an attribute of the class, to avoid the entire possibility of subclasses).
There are a few rare edge cases where it is possible to safely call destructors, but they are generally a sign of bad design and are easy to avoid if you manage to happen across one of them.
As an aside, note that std::shared_ptr type-erases its deleter, so std::shared_ptr<Base> will work even if Base does not have a public destructor.
Your base class has an implicit destructor. All will be fine.
A virtual base class destructor is used to allow a derived constructor to run when destructing via a pointer or reference to the base class. So in your case, this would be unsafe:
void destruct(Base &b) { b.~Base(); }
Derived d; destruct(d);
But this will be perfectly safe:
void destruct(Derived &d) { d.~Derived(); }
Derived d; destruct(d);
I have written a pure virtual destructor and implemented it in the abstract base class and override it in derived classes.
However, in one of the classes I have a pointer to a base class object.
Now, should the destructor of the derived class be written this way:
virtual ~DerivedClass()
{
delete this->pointerToAnotherDerivedClassObject;
}
or will the object be deleted automatically? As the base class destructor is always called so I cannot decide whether it takes care of it or not.
EDIT: My mistake for stating it was a pointer to a base class, as it is actually a pointer for another derived class object.
However, in one of the classes I have a pointer to a base class object.
Now, should the destructor of the derived class be written this way
Since pointerToAnotherDerivedClassObject points at another object in memory, then yes, your DerivedClass destructor needs to explicitly delete that object (or wrap the raw pointer inside a smart pointer - std::auto_ptr, std::unique_ptr, or std::shared_ptr - and let it delete the object for you) ONLY IF DerivedClass is meant to own that other object. Otherwise, do not delete it if you do not own it.
#Elia Similar situation is discussed in the book of Eckel " thinking in C++ vol-2 " in design pattern chapter-10 regarding pseudo virtual constructor. The answer to your question is you do need to delete it considering you allocate it dynamically. Also don't confuse member Base* with the Base object which is part of derived due to inheritance, one is a data member (which is what you want to delete) other is due to inheritance.
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.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
When to use virtual destructors?
If all the data members of a class (which has virtual function) and it's inherited class are of non pointer type (means it can not hold any dynamic memoroy), is it required to declare destructor as virtual?
Example
class base {
int x;
public:
virtual void fn(){}
};
class der: public base {
int y;
public:
void fn(){}
};
Here do we need a virtual destructor?
No, it's not always necessary. It's just a rule of thumb, and thus not always applicable.
The real rules says:
A destructor must be declared virtual when objects of derived classes are to be deleted through base class pointers.
Otherwise, deleting a derived class object through a base class pointer invokes undefined behavior. (The most likely outcome is that only the base class' destructor is called.)
Of course, that rule is quite a mouthful for newbies, hence the simpler rule of thumb, which is almost always right. It is very likely that you are managing dynamically created derived class objects through base class pointers in a polymorphic class hierarchy, and it is very unlikely that you do this for non-polymorphic class hierarchies.
A virtual destructor ensures that the inherited class destructor is called when you have a pointer to a base class.
In this particular case you don't need it, but a user could inherite from der another class (let it be foo) which uses -for example- dynamic memory allocation. In that case the destructor wouldn't be called unless he has a pointer of type foo.
So no, it's not "necessary" but if you already have at least a virtual function (hence you already have a VTABLE) there is no harm either. It's mandatory if you assume that those class are to be inherited by the user and are freed using a pointer to the base class.
No, it is not required and doing so at all times can even hurt performance.
You don't run into UB (undefined behavior) unless you delete a base class pointer actually storing a derived class object. So whether you need a virtual destructor depend on how your code actually creates and frees objects, not on the class alone.
Btw it doesn't matter whether a derived class requires any extra destruction compared to a base class - lacking a virtual destructor in case when delete is applied to a base class pointer storing a derived class object address is UB anyway.
Yes.
Anytime you create a class with a virtual function you need to declare the destructor also as virtual.
Consider this situation -
base *b = new der();
delete b;
Since you are operating on the base pointer, it doesn't know that it is actually an object of the child class and hence the destructor of the der is never called. Which might invaraibly lead memory leaks among other issues.