2009-10-16 81 views
1

正如我在另一個SO問題中指出的,我遇到了this article。當我通過MSVC7.1編譯boost 1.40並彈出幾個C4251警告時,問題就出現了。導出模板代碼=危險? (MSVC)

現在,在閱讀了上述文章之後,我想知道:通常不希望導出模板代碼,例如,

class DLLEXPORT_MACRO AClass 
{ 
public: 
    std::vector<int> getVecCopy() { return myVec; } 
    ... 
} 

說這個代碼通過MSVC7.1編譯成DLL。 雖然此代碼從其他MSVC7.1代碼引用時不會產生任何錯誤,但據說在MSVC8代碼中引用此DLL會在運行時產生崩潰(內存對齊問題?)。

由於這顯然是不好的...什麼是「最佳實踐」,以應付出口模板代碼的問題?

回答

6

這似乎是一個壞主意,因爲std :: vector在編譯器版本上不同或可能不同。但是,這可能會在加載時失敗,因爲std :: vector的名稱在編譯器版本中應該有所不同(這是名稱修改的基本原理的一部分)。

儘管作爲開發人員無法真正實施這種鏈接時失敗,但購買支持它的編譯器除外。另一種解決方案是將模板類型完全保留在DLL接口之外。把它們放入私人成員。

請注意,問題不是模板所特有的。想象一下,std::string是UDT而不是typedef,並且由編譯器運行時提供。它仍然可以在編譯器版本和編譯器廠商之間改變。它在DLL接口中仍然不可用。

由於這些原因,實際的解決方案是0.使用C,1.使用COM或2.解決單個編譯器版本。

+3

這是一般C++ ABI問題的一個方面,其中臭名昭着的「脆弱基類」問題是另一種特殊情況。從DLL導出模板接口只是一場等待發生的災難。我的首選解決方案是MSalters'0的一個變體:不是直接從DLL中導出C++,而是使用C綁定提供一個精簡的導出層,對象指針作爲不透明的句柄來回傳遞給客戶端。這樣客戶端不能直接與特定於編譯器的對象內部進行交互,所以它不能有這個問題。 –

+0

感謝您的洞察力。雖然(1)不會被考慮在內,但我認爲我可以分別與Bob(0)或(0')一樣生活。事實上,我想知道爲什麼boost :: program_options正在創造一個「等待發生的災難」,儘管如此。 – msi

0

不幸的是,真的沒有辦法導出模板代碼。外部庫通常只提供任何模板的源代碼。有時他們有模板使用輔助類,而不是模板來隱藏專有代碼。但基本上沒有辦法做到這一點。