12
votes

Suppose I have this code

class Base{
  public:
        int getVal();
  private:
         int a, b;
};

class Derived::public Base{
    public:
         void printVal();
};

int main(){
    Base *b = new Derived();
    delete b;    
}

I know a virtual destructor would delete things properly, but is it bad to delete with base pointer (when there is no virtual destructor) even if there are no virtual functions and no data members in the derived class? What will happen if this is done?

3

3 Answers

9
votes

Is it bad to delete with base pointer (when there is no virtual destructor) even if there are no virtual functions and no data members in the derived class?

Yes.

The behavior is undefined regardless the contents of the derived class.

What will happen if this is done?

Anything could happen.

7
votes

For primitive-type data, your example will most likely work in practice. As a matter of fact, incurring a vtable could actually hinder performance (so there may be some legitimate use here), but it is technically undefined, per 5.3-5.4:

If the static type of the operand [of the delete operator] 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 behaviour is undefined.

It really all depends on the "heapness" of the data in your class, and as there are no heap-allocated members (in your case), you should be fine, but it's definitely a code smell.

2
votes

The virtual desctructor in the derived class is needed in order to properly call the derived destructor (polymorphism), when the derived object is created through a pointer to the base class.

High Integrity CPP Rule 3.3.2 Write a 'virtual' destructor for base classes. (QACPP 2116)

Justification: If an object will ever be destroyed through a pointer to its base class, then that base class should have a virtual destructor. If the base class destructor is not virtual, only the destructor for the base class will be invoked. In most cases, destructors should be virtual, because maintenance or reuse may add derived classes that require a virtual destructor.

class Base {}; 
class Derived : public Base { public: ~Derived() {} }; 

void foo() {  
   Derived* d = new Derived; delete d; // correctly calls derived destructor 
} 
void boo() { 
   Derived* d = new Derived; Base* b = d; delete b; // problem! does not call derived destructor! 
}