Kevin Dill
Kevin Dill

Reputation: 186

C++11: Can I explicitly call a base class destructor to destroy the derived class?

I'm implementing a memory pool in C++11. All objects stored in the memory pool are required to inherit from the MemoryPoolObject class, but they may use multiple inheritance.

When I allocate a new object, I use malloc to create it, and then use the placement constructor - which I can do, because I know it's type (allocate() is a template function that takes the type as a template argument). I also store its size on the object on it (as a member variable of the MemoryPoolObject class).

When I deallocate the object, I want to call its destructor. but I no longer know the object type. I do know that it derives from MemoryPoolObject, which has a virtual destructor. So... if I make an explicit call to ~MemoryPoolObject(), will that do the right thing (including calling into the destructors of any multiply inherited base classes)?

Here's some code. It doesn't show how the unused objects get stored and retrieved in the pool. but that's really not relevant to the question at hand.

class BaseClass
{
public:
    virtual ~BaseClass();
    ...
};

class MemoryPoolObject
{
public:
    virtual ~MemoryPoolObject();

    // In reality I don't just expose this, but for simplicity...
    size_t m_ObjectSize;
};

class ChildClass : public BaseClass, public MemoryPoolObject
{
    virtual ~ChildClass();
    ...
};

// allocation (simplified)
template<class T> 
T* allocate()
{
    size_t objectSize = sizeof(T);
    T* obj = (T*)malloc(objectSize);
    new(obj) T();
    obj->m_ObjectSize = objectSize;
}

// deallocation (also simplified)
void deallocate(MemoryPoolObject* obj)
{
    // Does this call ~BaseClass() and ~ChildClass()?
    obj->~MemoryPoolObject();
}

Upvotes: 1

Views: 560

Answers (1)

R Sahu
R Sahu

Reputation: 206707

So... if I make an explicit call to ~MemoryPoolObject(), will that do the right thing (including calling into the destructors of any multiply inherited base classes)?

Yes, it will.

However, I think you can change strategy a bit to make your code more intuitive.

Overload the operator new and operator delete in MemoryPoolObject and let users use operator new and operator delete in the usual way.

An example program:

#include <iostream>
using namespace std;

void* allocate(size_t s)
{
   // This is a simple implementation.
   // To use a memory pool for allocating objects, this function
   // and deallocate() need to be changed accordingly.

   std::cout << "Allocating memory of size " << s << std::endl;
   return new char[s];
}

void deallocate(void* ptr, size_t s)
{
   std::cout << "Dellocating memory of size " << s << std::endl;
   delete [] static_cast<char*>(ptr);
}

class MemoryPoolObject
{
   public:

      virtual ~MemoryPoolObject() {}

      void* operator new (size_t s)
      {
         return allocate(s);
      }

      void operator delete (void* ptr, size_t s)
      {
         return deallocate(ptr, s);
      }
};

class BaseClass
{
   public:
      virtual ~BaseClass() {}
};

class ChildClass : public BaseClass, public MemoryPoolObject
{
   virtual ~ChildClass() {}
};

int main()
{
   MemoryPoolObject* ptr = new ChildClass;
   delete ptr;
}

Output

Allocating memory of size 16
Dellocating memory of size 16

Upvotes: 6

Related Questions