2015-08-19 52 views
2

我讀過幾次,傳遞STL對象,如向量和字符串在DLL邊界之外是不好的做法,因爲不同的編譯器版本可以爲STL對象生成不同的代碼。因此,你應該設計一個C風格的接口,而不是傳遞STL對象。然而,還有一些事情我不清楚:正確定義DLL接口與C++ 11/14

1.什麼是DLL的「邊界」?

是否正確地說,邊界是代碼在哪裏編譯在DLL端編譯爲?如果我在一個DLL中定義一個.h文件(編寫一個工廠類)並在不同的項目中使用該頭文件,該怎麼辦?那個.h文件是在DLL的邊界之內還是之外,爲什麼?

2.什麼是包含在DLL中?

讓我們說我有一個類Foo:

class Foo 
{ 
public: 
    __declspec(dllexport) void f1(); //instantiates v1 inside function 
private: 
    unique_ptr<vector<int>> v1 = nullptr; 
} 

如果我只標註函數f1()與__declspec(dllexport)的,只有這個功能應該被包含在DLL。如果v1不包含在DLL中,f1()中的代碼如何知道v1是什麼?

3.使用的unique_ptr

我使用的unique_ptr幾乎每次在我的項目傳遞出一個DLL邊界的對象。據我所知,從DLL返回unique_ptr將是不好的做法,因爲unique_ptr是一個STL對象。我如何實例化DLL中的對象並返回unique_ptr?

4.爲什麼定義接口或使用PIMPL有助於定義DLL接口?

我仍然必須將我的STL類轉換爲C樣式的對象。而在使用該DLL的項目中,我將不得不以某種方式再次在STL類中包裝C風格的對象。在這種情況下,我沒有看到使用接口或PIMPL的好處。另外,如果我定義了一個接口(具有純虛擬函數的類),那麼這與用__declspec(dllexport)聲明我的類中的函數是否具有相同的效果?

class IFoo 
{ 
public: 
    virtual ~IFoo() = 0 {}; 
    virtual void f1() = 0; 
} 
class Foo : public IFoo 
{ 
public: 
    void f1(); 
    //__declspec(dllexport) void f1(); //why use an interface if I can just declare the functions like this? 
} 

在現代C++ 11/14庫中如何解決DLL-STL問題?有沒有我可以看看的現代開源庫?

+0

當然,選項並不是爲每個支持的編譯器混合編譯器版本或構建單獨的庫。 [Boost做到這一點](http://sourceforge.net/projects/boost/files/boost-binaries/1.59.0/) –

+0

這可能是最簡單的解決方案,我想這樣做,因爲確保便攜DLL似乎是一場真正的鬥爭。一般來說,這對商業項目來說是否可以接受? – user3067395

回答

1

不幸的是,STL類型在編譯器中不一致。即使不同版本的Visual Studio也有不同之處。

邊界是編譯代碼的地方。如果在庫中的頭文件中有一個實現,則用於編譯EXE的編譯器將編譯該代碼。這可能非常糟糕,因爲EXE中的代碼認爲數據與DLL中的代碼認爲數據不同。 (如果你在結構定義中有#ifs,並且你需要明確包裝),你需要注意這種差異。

唯一確定的方法是定義所有你自己的類型(小心打包)而不使用STL。這是DLL庫通常所做的。

接口可以使用戶動態鏈接到庫。使用__declspec(dllexport)需要靜態鏈接;即EXE必須鏈接到編譯DLL時生成的.lib才能訪問所有函數。這意味着除其他外,如果沒有必要重新編譯EXE,則無法更新DLL(可能 - 在某些情況下可以避免這種情況,但這不是一個好主意)。

通過動態鏈接,您可以更新DLL或向DLL添加功能,而無需重新鏈接EXE,只要您不更改接口即可。 EXE可能調用DLL上的LoadLibrary()和GetProcAddress()來訪問一個返回接口的函數。其他所有包括作爲參數傳遞的數據類型的都是接口(即僅包含純虛函數)或簡單結構。這是COM的基本工作原理。

0

要回答問題2,當您聲明某些內容爲__declspec(dllexport)時,您將指出這是DLL接口的一部分 - 加載該DLL的組件可以訪問這些內容。任何聲明爲__declspec(dllexport)的內容都應該存在於DLL中,但不能被外部組件調用/使用。

+0

所以基本上,所有的代碼都包含在.dll中,但只有使用__declspec(dllexport)聲明的代碼是公共的,謝謝! – user3067395