問題描述
我正在嘗試從包含 std::vectors
和 std::strings
等對象的 DLL 中導出類 - 整個類被聲明為 DLL 導出通過:
class DLL_EXPORT FontManager {
問題是,對于復雜類型的成員,我收到此警告:
<塊引用>warning C4251: 'FontManager::m__fonts' : class 'std::map<_Kty,_Ty>'需要有 dll 接口供FontManager"類的客戶端使用和[_Kty=std::string,_Ty=tFontInfoRef]
即使我沒有更改成員變量本身的類型,我也可以通過將以下前向類聲明放在它們之前來刪除一些警告:
模板類 DLL_EXPORT std::allocator;模板類 DLL_EXPORT std::vector>;std::vectorm_glyphProviders;
看起來像前向聲明injects"編譯成員時的 DLL_EXPORT
但它安全嗎?
當客戶端編譯這個頭文件并在他身邊使用 std::
容器時,它真的改變了什么嗎?
它是否會在未來使用這種容器 DLL_EXPORT
(并且可能不是內聯的)?
并且它真的解決了警告試圖警告的問題嗎?
這個警告是我應該擔心的,還是最好在這些結構的范圍內禁用它?
客戶端和 DLL 將始終使用相同的庫和編譯器集構建,而這些只是頭文件類...
我使用的是帶有標準 STD 庫的 Visual Studio 2003.
更新
我想更多地針對您,因為我看到答案很籠統,這里我們談論的是 std 容器和類型(例如 std::string
)——也許問題真的很重要是:
我們能否通過相同的庫頭禁用對客戶端和 DLL 可用的標準容器和類型的警告,并像對待 int
或任何其他內置函數一樣對待它們?類型?(它似乎在我這邊工作正常)
如果是這樣,我們應該在什么條件下才能做到這一點?
或者是否應該禁止使用此類容器,或者至少要格外小心以確保不會將賦值運算符、復制構造函數等內聯到 DLL 客戶端中?
總的來說,我想知道您是否覺得設計具有此類對象的 DLL 接口(例如使用它們將內容作為返回值類型返回給客戶端)是否是一個好主意,以及為什么,我會喜歡有高水平"此功能的接口...
也許最好的解決方案是 Neil Butterworth 建議的 - 創建一個靜態庫?
當您從客戶端訪問類中的成員時,您需要提供一個 DLL 接口.DLL 接口意味著編譯器在 DLL 本身中創建函數并使其可導入.
因為編譯器不知道 DLL_EXPORTED 類的客戶端使用哪些方法,所以它必須強制所有方法都是 dll 導出的.它必須強制客戶端可以訪問的所有成員也必須 dll 導出它們的函數.當編譯器警告您未導出的方法以及客戶端的鏈接器發送錯誤時,就會發生這種情況.
不是每個成員都必須用 dll-export 標記,例如客戶無法接觸的私人成員.在這里您可以忽略/禁用警告(注意編譯器生成的 dtor/ctors).
否則成員必須導出他們的方法.使用 DLL_EXPORT 向前聲明它們不會導出這些類的方法.您必須在其編譯單元中將相應的類標記為 DLL_EXPORT.
它歸結為...(對于非 dll 可導出成員)
如果您的成員不能/不能被客戶使用,請關閉警告.
如果您有必須由客戶端使用的成員,請創建一個 dll 導出包裝器或創建間接方法.
要減少外部可見成員的數量,請使用PIMPL idiom.
<小時>
模板類 DLL_EXPORT std::allocator;
這確實在當前編譯單元中創建了模板特化的實例化.所以這會在dll中創建std::allocator的方法并導出對應的方法.這不適用于具體類,因為這只是模板類的實例化.
I'm trying to export classes from a DLL that contain objects such as std::vectors
and std::strings
- the whole class is declared as DLL export through:
class DLL_EXPORT FontManager {
The problem is that for members of the complex types I get this warning:
warning C4251: 'FontManager::m__fonts' : class 'std::map<_Kty,_Ty>' needs to have dll-interface to be used by clients of class 'FontManager' with [ _Kty=std::string, _Ty=tFontInfoRef ]
I'm able to remove some of the warnings by putting the following forward class declaration before them even though I'm not changing the type of the member variables themselves:
template class DLL_EXPORT std::allocator<tCharGlyphProviderRef>;
template class DLL_EXPORT std::vector<tCharGlyphProviderRef,std::allocator<tCharGlyphProviderRef> >;
std::vector<tCharGlyphProviderRef> m_glyphProviders;
Looks like the forward declaration "injects" the DLL_EXPORT
for when the member is compiled but is it safe?
Does it really change anything when the client compiles this header and uses the std::
container on his side?
Will it make all future uses of such a container DLL_EXPORT
(and possibly not inline)?
And does it really solve the problem that the warning tries to warn about?
Is this warning anything I should be worried about or would it be best to disable it in the scope of these constructs?
The clients and the DLL will always be built using the same set of libraries and compilers and those are header only classes...
I'm using Visual Studio 2003 with the standard STD library.
Update
I'd like to target you more though as I see the answers are general and here we're talking about std containers and types (such as std::string
) - maybe the question really is:
Can we disable the warning for standard containers and types available to both the client and the DLL through the same library headers and treat them just as we'd treat an int
or any other built-in type? (It does seem to work correctly on my side)
If so would should be the conditions under which we can do this?
Or should maybe using such containers be prohibited or at least ultra care taken to make sure no assignment operators, copy constructors etc will get inlined into the DLL client?
In general I'd like to know if you feel designing a DLL interface having such objects (and for example using them to return stuff to the client as return value types) is a good idea or not and why, I'd like to have a "high level" interface to this functionality...
Maybe the best solution is what Neil Butterworth suggested - creating a static library?
When you touch a member in your class from the client, you need to provide a DLL-interface. A DLL-interface means, that the compiler creates the function in the DLL itself and makes it importable.
Because the compiler doesn't know which methods are used by the clients of a DLL_EXPORTED class it must enforce that all methods are dll-exported. It must enforce that all members which can be accessed by clients must dll-export their functions too. This happens when the compiler is warning you of methods not exported and the linker of the client sending errors.
Not every member must be marked with with dll-export, e.g. private members not touchable by clients. Here you can ignore/disable the warnings (beware of compiler generated dtor/ctors).
Otherwise the members must export their methods. Forward declaring them with DLL_EXPORT does not export the methods of these classes. You have to mark the according classes in their compilation-unit as DLL_EXPORT.
What it boils down to ... (for not dll-exportable members)
If you have members which aren't/can't be used by clients, switch off the warning.
If you have members which must be used by clients, create a dll-export wrapper or create indirection methods.
To cut down the count of externally visible members, use approaches such as the PIMPL idiom.
template class DLL_EXPORT std::allocator<tCharGlyphProviderRef>;
This does create an instantiation of the template specialization in the current compilation unit. So this creates the methods of std::allocator in the dll and exports the corresponding methods. This does not work for concrete classes as this is only an instantiation of template classes.
這篇關于從 DLL 導出包含 `std::` 對象(向量、映射等)的類的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!