Search code examples
c++dlldelete-operatorvirtual-destructor

How can I properly delete a derived object I received from another DLL?


In my scenario I have a DLL with a base class. This DLL can load plugins. Each plugin DLL exports a create function which returns a derived object. I would prefer if the objects from the plugin DLLs could delete themselves.

In the following, I have written down two ways. Please ignore missing public/private statements. The first way is of course simpler because I only need to call delete as usual, but I am not sure whether it works. The second way does an explicit delete this because this must have the derived type, right?

// main DLL

class Base1
{
    virtual ~Base(){}
};

class Base2
{
    virtual ~Base(){}
    virtual void destroy() = 0;
};

// plugin DLL without destroy
class Derived1 : public Base1
{
    Derived1()
    {
        m_p = new cSomeClass;
    }

    virtual ~Derived1()
    {
        delete m_p;
    }

    cSomeClass * m_p;
}

// function which is exported
Base1 * createDerived1()
{
    return new Derived1;
}

// plugin DLL with destroy
class Derived2 : public Base2
{
    Derived2()
    {
        m_p = new cSomeClass;
    }

    virtual ~Derived2()
    {
        delete m_p;
    }

    virtual void destroy()
    {
        delete this;
    }

    cSomeClass * m_p;
}

// function which is exported
Base2 * createDerived2()
{
    return new Derived2;
}


int main()
{
    Base1 * pBase1 = createDerived1();
    delete pBase1;
    pBase = nullptr;
    // is derived object properly deleted?

    Base2 * pBase2 = createDerived2();
    pBase2->destroy();
    pBase2 = nullptr;
    // is derived object properly deleted?

}

Which one does "the right thing", i.e. properly delete the derived object using a base class pointer?

  1. delete knows the object type and will properly delete it because of the virtual destructor.
  2. Write a pure virtual destroy method which is implemented in the derived classes.
  3. Export a destroy() method next to the create method which takes a Base pointer and does a dynamic cast before delete. (I have not written an example for this case because I find it unattractive.)

The first way seems to be the simplest because it does not require work beside properly writing virtual destructors.


Solution

  • Memory management between DLLs is a real pain.

    In general memory allocated in one DLL must not be released in another.

    Providing an explicit destroy (delete this) function, that must be called when the object is no longer needed, is the typical solution.

    So go for 2 (write a pure virtual destroy method which is implemented in the derived classes):

    class IBase
    {
    public:
      virtual void destroy() = 0;
    
      // Other pure virtual methods.
    };
    
    class Derived : public IBase
    {
    public:
       Derived() { m_p = new cSomeClass; }
    
       virtual ~Derived() { delete m_p; }
    
       virtual void destroy() override { delete this; }
    
    private:
       cSomeClass *m_p;
    };
    
    extern "C" __declspec(dllexport) IBase * __cdecl createDerived()
    {
      return new Derived;
    }
    

    For further details you can read the GREAT Exporting C++ classes from a DLL (from Eli Bendersky's website).