代码之家  ›  专栏  ›  技术社区  ›  Flamefire

如何处理DLL导出接口中的析构函数

  •  5
  • Flamefire  · 技术社区  · 9 年前

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

    安全的方法是什么?自由/释放功能应如何实施?

    1 回复  |  直到 9 年前
        1
  •  5
  •   Matthieu M.    9 年前

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

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

    因此,只要有一个 virtual 析构函数应该工作。由于通过虚拟表进行调用,因此不会出现名称损坏问题。

    此外,请注意,在现代C++中,返回原始指针是一个no no,但名称损坏会阻止使用智能指针。。。

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