Search code examples
c++memory-leaksvirtualradixderived-class

Memory leak caused by pointer to derived class


Why does this code cause memory leak? It's said that if the base class destructor is made "virtual", the memory leak problem would be solved. Why?

class base {
 public: 
   base () { ptr = new int[1024]; }
   ~base () { delete [] ptr; }
 private:
   double *ptr;
};
class der : public base {
 public:
   der () { name = new char[1024]; }
   ~der () { delete [] name; }
 private:
   char *name;
};
int main () {
  base* aPointer = new derived;
  delete aPointer;
  return 0;
}

Solution

  • It leaks, and it's Undefined Behaviour.

    If your derived class didn't introduce extra heap-allocated variables, then it probably wouldn't but would still be Undefined Behaviour so speculation's pointless.

    Unless base has a virtual destructor, deletion of derived objects using a base* will fail to call destructors for the further derived classes and their members and other bases... here name would not be deallocated.

    It's said that if the base class destructor is made "virtual", the memory leak problem would be solved. Why?

    virtual functions are the way the compiler coordinates calls to derived-class-specific functions from code that only has a pointer or reference to the base class. This is a fundamental aspect of Object Oriented Programming support in C++, and if you don't understand it you should get a good book or online tutorial, but to give a very concise introduction: a virtual function works a bit like having a function pointer in the base class that normally points to the base class's function implementation, but if a derived class constructor runs then the function pointer is overwritten with the address of its own implementation (in practice virtual dispatch tends to use class-specific tables of function pointers for better memory efficiency, but the observable functionality is similar to what I've described). So, your derived destructor won't run when you delete using a pointer with static type of base* unless it's virtual - there's no function-pointer-like indirection coordinated by the derived type that could arrange this.