Deleting a derived class object using a pointer to a base class that has a non-vitrual destructor results in undefined behavior. To correct this situation, the parent class should be defined with a virtual destructor.
Non-Compliant Code Example
In this non-compliant example, a reference to the parent class Base
is used to instantiate a Derived
object. When b
is deleted, the destructor for Base
is invoked rather than the destructor for Derived
. As a result, the object b
refers to is not properly destroyed.
class Base { public: Base() { // Build Base object } ~Base() { // Destroy Base object } }; class Derived : public Base { public: Derived() { // Build Derived object } ~Derived() { // Destroy Derived object } }; void function(void) { Base *b = new Derived(); // ... delete b; }
Compliant Solution
To correct this example, the destructor for Base
should be declared virtual
. This ensures that the object b
refers to is correctly evaluated at runtime and that deleting b
will call the destructor for class Derived
.
class Base { public: Base() { // Build Base object } virtual ~Base() { // Destroy Base object } }; class Derived : public Base { public: Derived() { // Build Derived object } ~Derived() { // Destroy Derived object } }; void function(void) { Base *b = new Derived(); // ... delete b; }
Destructors are not virtual by default because many classes are not designed to be used as base classes. Virtual functions only make sense in classes that act as interfaces to objects of derived classes.
Risk Assessment
Calling the wrong destructor for a polymorphic object may lead to resource mismanagement and possibly unintended program behavior.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
OBJ02-A |
2 (medium) |
2 (probable) |
2 (medium) |
P6 |
L2 |
References
*[[Stroustrup 06]] Why are destructors not virtual by default?