2015-09-07 60 views
1

我試圖從DLL中導出類。我讀了這樣的這篇文章:http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL如何處理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

不要讓事情變得更復雜得多,他們需要成爲。只需在IFoo中提供一個虛擬析構函數並導出其定義。 –

+0

您可以改爲將虛擬Free()函數添加到接口。將* inst *投射到Foo *是另一種方式,不是更好。 –

+0

@HansPassant:爲什麼不簡單地使用虛擬析構函數? –

回答

3

首先,我們注意到這個問題是特定於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 
+0

所以這個解決方案只是一個虛擬的析構函數,在DLL的cpp中實現? 而我堅持使用C++ 03 ATM可以實現與那個相同的受保護的構造函數嗎?內聯實現被禁止我猜... – Flamefire

+0

@Flamefire:我會認爲非內聯析構函數應該工作;我用內聯析構函數看到的問題是,它會爲析構函數生成多次代碼:每個DLL一次,因爲它們使用不兼容的版本......至於C++ 03,不要使用'Foo(Foo &&) '構造函數,並且當然寫完全身(因爲你不會有'= default')。 –