【问题标题】:How can I properly delete a derived object I received from another DLL?如何正确删除从另一个 DLL 收到的派生对象?
【发布时间】:2016-07-11 23:51:18
【问题描述】:

在我的场景中,我有一个带有基类的 DLL。此 DLL 可以加载插件。每个插件 DLL 都导出一个创建函数,该函数返回一个派生对象。我希望插件 DLL 中的对象可以自行删除。

在下文中,我写下了两种方法。请忽略缺少的公开/私人声明。第一种方式当然更简单,因为我只需要像往常一样调用delete,但我不确定它是否有效。第二种方法是显式的delete this,因为this 必须有派生类型,对吧?

// 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?

}

哪一个做“正确的事”,即使用基类指针正确删除派生对象?

  1. delete 知道对象类型,并且会因为虚拟析构函数而正确删除它。
  2. 编写一个在派生类中实现的纯虚拟销毁方法。
  3. 在 create 方法旁边导出一个 destroy() 方法,该方法采用 Base 指针并在 delete 之前进行动态转换。 (我没有为此案例编写示例,因为我觉得它没有吸引力。)

第一种方法似乎是最简单的,因为除了正确编写虚拟析构函数之外它不需要工作。

【问题讨论】:

  • dll和exe是否使用相同版本的C++运行库?他们使用相同的编译器选项吗?如果是,并且是;那么它将按预期工作。

标签: c++ dll delete-operator virtual-destructor


【解决方案1】:

DLL 之间的内存管理真的很痛苦。

一般来说,在一个 DLL 中分配的内存不能在另一个 DLL 中释放。

提供显式销毁 (delete this) 函数,当不再需要对象时必须调用该函数,这是典型的解决方案。

所以选择2(编写一个在派生类中实现的纯虚拟销毁方法):

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;
}

有关更多详细信息,您可以阅读 GREAT Exporting C++ classes from a DLL(来自 Eli Bendersky 的网站)。

【讨论】:

    【解决方案2】:

    子类中不需要单独的删除函数。更新到 ma​​nlio 帖子:

    //在header中定义抽象类和函数

    #ifdef _EXPORTING
    #define CLASS_DECLSPEC    __declspec(dllexport)
    #else
    #define CLASS_DECLSPEC    __declspec(dllimport)
    #endif
    class CLASS_DECLSPEC IBase
    {
    public:
      // implement function in parent class
      void destroy(){delete this;};
    
      virtual ~IBase(){};
    
      // Other pure virtual methods.
    };
    

    //在dll源中导入头文件

    class Derived : public IBase
        {
        public:
           Derived() { m_p = new cSomeClass; }
           virtual ~Derived() { delete m_p; }
        private:
           cSomeClass *m_p;
    };
    extern "C" __declspec(dllexport) IBase * __cdecl createDerived()
    {
      return new Derived;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-28
      • 1970-01-01
      • 2017-09-29
      • 2018-02-23
      • 2013-10-13
      • 2020-03-12
      • 2012-12-30
      • 2023-03-19
      相关资源
      最近更新 更多