We use a framework that relies on memcpy in certain functions. To my understanding I can give everything that is trivially copyable into these functions.
Now we want to use a simple class hierarchy. We are not sure whether we can have a class hierarchy that results in trivially copyable types because of the safe destruction. The example code looks like this.
class Timestamp; //...
class Header
{
public:
uint8_t Version() const;
const Timestamp& StartTime();
// ... more simple setters and getters with error checking
private:
uint8_t m_Version;
Timestamp m_StartTime;
};
class CanData : public Header
{
public:
uint8_t Channel();
// ... more setters and getters with error checking
private:
uint8_t m_Channel;
};
The base class is used in several similar subclasses. Here I omitted all constructors and destructors. Thus the classes are trivially copyable. I suppose though that the user can write a code that results in a memory leak like this:
void f()
{
Header* h = new CanData();
delete h;
}
Is it right that the class hierarchy without the virtual destructor is a problem even if all classes use the compiler's default destructor? Is it therefore right that I cannot have a safe class hierarchy that is trivially copyable?
This code
Header* h = new CanData();
delete h;
will trigger undefined behavior since §5.3.5/p3 states:
In the first alternative (delete object), if the static type of the object to be deleted is different from its
dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the
static type shall have a virtual destructor or the behavior is undefined
and regardless of not having dynamically allocated objects contained in your derived class (really bad if you have), you shouldn't do it. Having a class hierarchy without the base class virtual destructor is not a problem per se, it becomes a problem when you try to mix static and dynamic types with delete.
Doing memcpy on a derived class object smells of bad design to me, I would rather address the need for a "virtual constructor" (i.e. a virtual clone() function in your base class) to duplicate your derived objects.
You can have your class hierarchy that is trivially copyable if you make sure that your object, its subobjects and base classes are trivially copyable. If you want to prevent users referring to your derived objects via base classes you could, as Mark first suggested, render the inheritance protected
class Header
{
public:
};
class CanData : protected Header
{ ^^^^^^^^^
public:
};
int main() {
Header *pt = new CanData(); // <- not allowed
delete pt;
}
Notice that you won't be able to use base pointers at all to refer to derived objects due to §4.10/p3 - pointer conversions.
If you delete a pointer to a derived type held as its base type and you don't have a virtual destructor, the derived types destructor won't be called, whether it's implicitly generated or not. And whether its implicitly generated or not, you want it to be called. If the derived type's destructor wouldn't actually do anything anyway though, it might not leak anything or cause a problem. If the derived type holds something like a std::string, std::vector, or anything with a dynamic allocation, you want the dtors to be called. As a matter of good practice, you always want a virtual destructor for base classes whether or not the derived classes destructors need to be called (since a base class shouldn't know about what derives from it, it shouldn't make an assumption like this).
If you copy a type like so:
Base* b1 = new Derived;
Base b2 = *b1;
You will only invoke Bases copy ctor. The parts of the object which are actually from Derived will not be involved. b2 will not secretly be a Derived, it will just be a Base.
My first instinct is "don't do that - find another way, a different framework, or fix the framework". But just for fun let's assume that for certain your class copy doesn't depend in any way on the copy constructor of the class or any of its comprised parts being called.
Then since you're clearly inheriting to implement rather than to substitute the solution is easy: Use protected inheritance and your problem is solved, because they can no longer polymorphically access or delete your object, preventing the undefined behavior.
It's almost safe. In particular, there is no memory leak in
Header* h = new CanData();
delete h;
delete h calls the destructor of Header and then frees the memory pointed to by h. The amount of memory freed is the same as was initially allocated at that memory address, not the sizeof(Header). Since Header and CanData are trivial, their destructors do nothing.
However, you must provide a virtual destructor to base even if it does nothing (by requirement of the standard to avoid undefined behaviour). A common guideline is that a destructor for a base class must be either public and virtual or protected and nonvirtual
Of course, you must beware slicing as usual.
Thanks all for posting various suggestions. I try a summarizing answer with an additional proposal for the solution.
The prerequisite of my question was to reach a class hierarchy that is trivially copyable. See http://en.cppreference.com/w/cpp/concept/TriviallyCopyable and especially the requirement of a trivial destructor (http://en.cppreference.com/w/cpp/language/destructor#Trivial_destructor). The class cannot need a destructor implemented. This restricts the allowed data members, but is fine for me. The example shows only C-compatible types without dynamic memory allocation.
Some pointed out that the problem of my code is undefined behaviour, not necessarily a memory leak. Marco quoted the standard regarding this. Thanks, really helpful.
From my understanding of the answers, possible solutions are the following. Please correct me if I am wrong. The solution's point is that the implementation of the base class must avoid that its destructor can be called.
Solution 1: The proposed solutions use protected inheritance.
class CanData : protected Header
{
...
};
It works but avoids that people can access the public interface of Header. This was the original intention to have a base class. CanData needs to forward these functions to Header. In the consequece, I would reconsider to use composition instead of inheritance here. But the solution should work.
Solution 2: Header's destructor must be protected, not the base class as a whole.
class Header
{
public:
uint8_t Version() const;
const Timestamp& StartTime();
// ... more simple setters and getters with error checking
protected:
~Header() = default;
private:
uint8_t m_Version;
Timestamp m_StartTime;
};
Then no user can delete Header. This is fine for me, because Header has no purpose on its own. With public derivation, the public interface remains available to the user.
My understanding is that CanData needs not implement a destructor to call the base class's desctructor. All can use the default destructor. I am not completely sure about this though.
All in all, the answers to my questions in the end of the origial positing are:
Is it right that the class hierarchy without the virtual destructor is a problem even if all classes use the compiler's default destructor?
It is only a problem if your destructor is public. You must avoid that people can access you desctrutor, except for derived classes. And you must ensure that derived classes call (implicitely) the base class's destructor.
Is it therefore right that I cannot have a safe class hierarchy that is trivially copyable?
You can make your base class safe with protected inheritance or a protected desctructor. Then you can have a hierarchy of trivially copyable classes.
Related
I am reading Effective C++ Third Edition by Scott Meyers.
He says generally it is not a good idea to inherit from classes that do not contain virtual functions because of the possibility of undefined behavior if you somehow convert a pointer of a derived class into the pointer of a base class and then delete it.
This is the (contrived) example he gives:
class SpecialString: public std::string{
// ...
}
SpecialString *pss = new SpecialString("Impending Doom");
std::string *ps;
ps = pss;
delete ps; // undefined! SpecialString destructor won't be called
I understand why this results in error, but is there nothing that can be done inside the SpecialString class to prevent something like ps = pss from happening?
Meyers points out (in a different part of the book) that a common technique to explicitly prevent some behavior from being allowed in a class is to declare a specific function but intentionally don't define it. The example he gave was copy-construction. E.g. for classes that you don't want to allow copy-construction to be allowed, declare a private copy constructor but do not define it, thus any attempts to use it will result in compile time error.
I realize ps = pss in this example is not copy construction, just wondering if anything can be done here to explicitly prevent this from happening (other than the answer of "just don't do that").
The language allows implicit pointer conversions from a pointer to a derived class to a pointer to its base class, as long as the base class is accessible and not ambiguous. This is not something that can be overridden by user code. Furthermore, if the base class allows destruction, then once you've converted a pointer-to-derived to a pointer-to-base, you can delete the base class via the pointer, leading to the undefined behavior. This cannot be overridden by a derived class.
Hence you should not derive from classes that were not designed to be base classes. The lack of workarounds in your book is indicative of the lack of workarounds.
There are two points in the above that might be worth taking a second look at. First: "as long as the base class is accessible and not ambiguous". (I'd rather not get into the "ambiguous" point.) You can prevent casting a pointer-to-derived to a pointer-to-base in code outside your class implementation by making the base class private. If you do that, though, you should take some time to think about why you are inheriting in the first place. Private inheritance is typically rare. Often it would make more sense (or at least as much sense) to not derive from the other class and instead have a data member whose type is the other class.
Second: "if the base class allows destruction". This does not apply in your example where you cannot change the base class definition, but it does apply to the claim "generally it is not a good idea to inherit from classes that do not contain virtual [destructors]". There is another viable option. It may be reasonable to inherit from a class that has no virtual functions if the destructor of that class is protected. If the destructor of a class is protected, then you are not allowed to use delete on a pointer to that class (outside the implementations of the class and classes derived from it). So you avoid the undefined behavior as long as the base class has either a virtual destructor or a protected one.
There's two approaches that might make sense:
If the real problem is that string is not really meant to be derived from and you have control over it - then you could make it final. (Obviously not something you can do with your std::string though, since you dont control std::string)
If string is OK to derive from, but not to use polymorphically, you can remove the new and delete functions from SpecialString to prevent allocating one via new.
For example:
#include <string>
class SpecialString : std::string {
void* operator new(size_t size)=delete;
};
int main() {
SpecialString ok;
SpecialString* not_ok = new SpecialString();
}
fails to compile with:
code.cpp:9:27: error: call to deleted function 'operator new'
SpecialString* not_ok = new SpecialString();
^
code.cpp:4:9: note: candidate function has been explicitly deleted
void* operator new(size_t size)=delete;
Note this doesn't stop odd behaviour like:
SpecialString ok;
std::string * ok_p = &ok;
ok_p->something();
which will always call std::string::something, not SpecialString::something if you've provided one. Which may not be what you expect.
You don't have to check this in runtime if you prevent the error.
As your book says it is a good practice to use a virtual destructor in the base class (with implementation), and of course a destructor for the derived class, this way if you assign a pointer to the derived class - to the base class, it first gets destroyed as a base, and then as a derived object.
you can see an example here https://www.geeksforgeeks.org/virtual-destructor
see comment for more specific clarification
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);
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.
Is there ever a good reason to not declare a virtual destructor for a class? When should you specifically avoid writing one?
There is no need to use a virtual destructor when any of the below is true:
No intention to derive classes from it
No instantiation on the heap
No intention to store with access via a pointer to a superclass
No specific reason to avoid it unless you are really so pressed for memory.
To answer the question explicitly, i.e. when should you not declare a virtual destructor.
C++ '98/'03
Adding a virtual destructor might change your class from being POD (plain old data)* or aggregate to non-POD. This can stop your project from compiling if your class type is aggregate initialized somewhere.
struct A {
// virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // Will fail if virtual dtor declared
}
In an extreme case, such a change can also cause undefined behaviour where the class is being used in a way that requires a POD, e.g. passing it via an ellipsis parameter, or using it with memcpy.
void bar (...);
void foo (A & a) {
bar (a); // Undefined behavior if virtual dtor declared
}
[* A POD type is a type that has specific guarantees about its memory layout. The standard really only says that if you were to copy from an object with POD type into an array of chars (or unsigned chars) and back again, then the result will be the same as the original object.]
Modern C++
In recent versions of C++, the concept of POD was split between the class layout and its construction, copying and destruction.
For the ellipsis case, it is no longer undefined behavior it is now conditionally-supported with implementation-defined semantics (N3937 - ~C++ '14 - 5.2.2/7):
...Passing a potentially-evaluated argument of class type (Clause 9) having a non-trivial copy constructor, a non-trivial move constructor, or a on-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics.
Declaring a destructor other than =default will mean it's not trivial (12.4/5)
... A destructor is trivial if it is not user-provided ...
Other changes to Modern C++ reduce the impact of the aggregate initialization problem as a constructor can be added:
struct A {
A(int i, int j);
virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // OK
}
I declare a virtual destructor if and only if I have virtual methods. Once I have virtual methods, I don't trust myself to avoid instantiating it on the heap or storing a pointer to the base class. Both of these are extremely common operations and will often leak resources silently if the destructor is not declared virtual.
A virtual destructor is needed whenever there is any chance that delete might be called on a pointer to an object of a subclass with the type of your class. This makes sure the correct destructor gets called at run time without the compiler having to know the class of an object on the heap at compile time. For example, assume B is a subclass of A:
A *x = new B;
delete x; // ~B() called, even though x has type A*
If your code is not performance critical, it would be reasonable to add a virtual destructor to every base class you write, just for safety.
However, if you found yourself deleteing a lot of objects in a tight loop, the performance overhead of calling a virtual function (even one that's empty) might be noticeable. The compiler cannot usually inline these calls, and the processor might have a difficult time predicting where to go. It is unlikely this would have a significant impact on performance, but it's worth mentioning.
Virtual functions mean every allocated object increases in memory cost by a virtual function table pointer.
So if your program involves allocating a very large number of some object, it would be worth avoiding all virtual functions in order to save the additional 32 bits per object.
In all other cases, you will save yourself debug misery to make the dtor virtual.
Not all C++ classes are suitable for use as a base class with dynamic polymorphism.
If you want your class to be suitable for dynamic polymorphism, then its destructor must be virtual. In addition, any methods which a subclass could conceivably want to override (which might mean all public methods, plus potentially some protected ones used internally) must be virtual.
If your class is not suitable for dynamic polymorphism, then the destructor should not be marked virtual, because to do so is misleading. It just encourages people to use your class incorrectly.
Here's an example of a class which would not be suitable for dynamic polymorphism, even if its destructor were virtual:
class MutexLock {
mutex *mtx_;
public:
explicit MutexLock(mutex *mtx) : mtx_(mtx) { mtx_->lock(); }
~MutexLock() { mtx_->unlock(); }
private:
MutexLock(const MutexLock &rhs);
MutexLock &operator=(const MutexLock &rhs);
};
The whole point of this class is to sit on the stack for RAII. If you're passing around pointers to objects of this class, let alone subclasses of it, then you're Doing It Wrong.
A good reason for not declaring a destructor as virtual is when this saves your class from having a virtual function table added, and you should avoid that whenever possible.
I know that many people prefer to just always declare destructors as virtual, just to be on the safe side. But if your class does not have any other virtual functions then there is really, really no point in having a virtual destructor. Even if you give your class to other people who then derive other classes from it then they would have no reason to ever call delete on a pointer that was upcast to your class - and if they do then I would consider this a bug.
Okay, there is one single exception, namely if your class is (mis-)used to perform polymorphic deletion of derived objects, but then you - or the other guys - hopefully know that this requires a virtual destructor.
Put another way, if your class has a non-virtual destructor then this is a very clear statement: "Don't use me for deleting derived objects!"
If you have a very small class with a huge number of instances, the overhead of a vtable pointer can make a difference in your program's memory usage. As long as your class doesn't have any other virtual methods, making the destructor non-virtual will save that overhead.
I usually declare the destructor virtual, but if you have performance critical code that is used in an inner loop, you might want to avoid the virtual table lookup. That can be important in some cases, like collision checking. But be careful about how you destroy those objects if you use inheritance, or you will destroy only half of the object.
Note that the virtual table lookup happens for an object if any method on that object is virtual. So no point in removing the virtual specification on a destructor if you have other virtual methods in the class.
If you absolutely positively must ensure that your class does not have a vtable then you must not have a virtual destructor as well.
This is a rare case, but it does happen.
The most familiar example of a pattern that does this are the DirectX D3DVECTOR and D3DMATRIX classes. These are class methods instead of functions for the syntactic sugar, but the classes intentionally do not have a vtable in order to avoid the function overhead because these classes are specifically used in the inner loop of many high-performance applications.
On operation that will be performed on the base class, and that should behave virtually, should be virtual. If deletion can be performed polymorphically through the base class interface, then it must behave virtually and be virtual.
The destructor has no need to be virtual if you don't intend to derive from the class. And even if you do, a protected non-virtual destructor is just as good if deletion of base class pointers isn't required.
The performance answer is the only one I know of which stands a chance of being true. If you've measured and found that de-virtualizing your destructors really speeds things up, then you've probably got other things in that class that need speeding up too, but at this point there are more important considerations. Some day someone is going to discover that your code would provide a nice base class for them and save them a week's work. You'd better make sure they do that week's work, copying and pasting your code, instead of using your code as a base. You'd better make sure you make some of your important methods private so that no one can ever inherit from you.