【问题标题】:How to handle destructors in DLL exported interfaces如何处理 DLL 导出接口中的析构函数
【发布时间】:2015-09-07 18:49:14
【问题描述】:

我正在尝试从 DLL 中导出一个类。我在这样做时阅读了这篇文章:http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL

“成熟”的方法建议使用抽象类,所以我有:

// Header
class IFoo{
public:
    virtual int getBar() = 0;
}

class Foo: public IFoo {...}

DLLEXPORT IFoo* Create();
DLLEXPRT void Free(IFoo* inst);

//DLL cpp
IFoo* Create(){ return new Foo; }
void Free(IFoo* inst){ delete inst; }

让我困惑的是:如果我没有虚拟析构函数,那么delete inst 不会调用 Foos 析构函数并且可能会泄漏内存。我该怎么处理?这篇文章没有给出答案。

使用 virtual ~IFoo(){} 是不可能的,因为这会向 IFoo 添加一个实现,这会导致问题(在文章中关于内联虚函数的问题的答案中进行了解释),并且 virtual ~IFoo() = 0; 失败并出现未定义的链接器错误符号~IFoo

什么是安全的方法? Free/Release功能应该如何实现?

【问题讨论】:

  • 不要让事情变得过于复杂。只需在IFoo 中提供一个虚拟析构函数并导出它的定义。
  • 您可以在界面中添加一个虚拟的 Free() 函数。将 inst 转换为 Foo* 是另一种方式,不是更好。
  • @HansPassant:为什么不简单地使用虚拟析构函数?
  • 我只是给他子弹,装枪是他的事。

标签: c++ dll destructor dllexport pure-virtual


【解决方案1】:

首先,让我们注意这个问题是特定于 Visual Studio 对 DLL 的处理。 GCC 和 Clang 都有一个稳定的 ABI (Itanium ABI),保证了不同版本编译的库的兼容性。

现在,如前所述,您在这里面临的问题是 ABI 不稳定,但是 ABI 的某些部分是稳定的(虚拟表布局),否则所提出的策略根本不起作用。

因此,只需使用 virtual 析构函数就可以了。由于是通过虚拟表调用,所以不会出现名称混淆问题。

另外,请注意,在现代 C++ 中返回原始指针是不允许的,但名称修改会阻止使用智能指针...

// Foo.h
class Foo {
public:
    virtual int get() = 0;
    virtual ~Foo();

protected:
    Foo() = default;
    Foo(Foo&&) = default;
    Foo(Foo const&) = default;
    Foo& operator=(Foo) = default;
};

// WARNING: immediately capture this Foo* in a smart pointer,
//          or suffer from memory leak (and worse).
Foo* createFoo(); // factory behind

// Foo.cpp
Foo::~Foo() {} // not inline

【讨论】:

  • 所以解决方案只是在 DLLs cpp 中实现的虚拟析构函数?而且我被 C++03 ATM 卡住了,我可以用它来实现相同的受保护构造函数吗?我猜内联实现是被禁止的......
  • @Flamefire:我认为非内联析构函数应该可以工作;我看到的内联析构函数的问题是,它将为析构函数生成多次代码:每个 DLL 一次,并且由于它们使用不兼容的版本......至于 C++03,只是不要使用 Foo(Foo&&) 构造函数,当然还有完整的正文(因为你不会有= default)。
猜你喜欢
  • 2015-09-02
  • 1970-01-01
  • 2014-03-22
  • 1970-01-01
  • 2012-12-29
  • 2011-01-17
  • 2017-07-12
  • 2019-07-14
  • 2021-11-06
相关资源
最近更新 更多