C++ 如何在DLL导出接口中处理析构函数

C++ 如何在DLL导出接口中处理析构函数,c++,dll,destructor,dllexport,pure-virtual,C++,Dll,Destructor,Dllexport,Pure Virtual,我正在尝试从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

我正在尝试从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功能?

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

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

因此,只要有一个
虚拟的
析构函数就可以了。由于通过虚拟表进行调用,因此不会出现名称损坏问题

也注意到,在现代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

不要把事情弄得太复杂。只需在
IFoo
中提供一个虚拟析构函数并导出其定义。您可以改为在接口中添加一个virtual Free()函数。将inst转换成Foo*是另一种方式,不是更好。@HansPassant:为什么不简单地做一个虚拟析构函数呢?我只是把子弹交给他,装枪由他决定。所以解决方案就是在DLL cpp中实现一个虚拟析构函数?我一直在使用C++03 ATM,我能用它实现同样的受保护构造函数吗?内联实现是被禁止的,我想…@Flamefire:我认为非内联析构函数应该可以工作;我看到的内联析构函数的问题是,它将为析构函数生成多次代码:每个DLL生成一次,而且由于它们使用不兼容的版本。。。对于C++03,只需不要使用
Foo(Foo&&)
构造函数,当然要完整地编写主体(因为您没有
=default
)。