問(wèn)題描述
我正在嘗試從包含 std::vectors
和 std::strings
等對(duì)象的 DLL 中導(dǎo)出類 - 整個(gè)類被聲明為 DLL 導(dǎo)出通過(guò):
class DLL_EXPORT FontManager {
問(wèn)題是,對(duì)于復(fù)雜類型的成員,我收到此警告:
<塊引用>warning C4251: 'FontManager::m__fonts' : class 'std::map<_Kty,_Ty>'需要有 dll 接口供FontManager"類的客戶端使用和[_Kty=std::string,_Ty=tFontInfoRef]
即使我沒有更改成員變量本身的類型,我也可以通過(guò)將以下前向類聲明放在它們之前來(lái)刪除一些警告:
模板類 DLL_EXPORT std::allocator;模板類 DLL_EXPORT std::vector>;std::vectorm_glyphProviders;
看起來(lái)像前向聲明injects"編譯成員時(shí)的 DLL_EXPORT
但它安全嗎?
當(dāng)客戶端編譯這個(gè)頭文件并在他身邊使用 std::
容器時(shí),它真的改變了什么嗎?
它是否會(huì)在未來(lái)使用這種容器 DLL_EXPORT
(并且可能不是內(nèi)聯(lián)的)?
并且它真的解決了警告試圖警告的問(wèn)題嗎?
這個(gè)警告是我應(yīng)該擔(dān)心的,還是最好在這些結(jié)構(gòu)的范圍內(nèi)禁用它?
客戶端和 DLL 將始終使用相同的庫(kù)和編譯器集構(gòu)建,而這些只是頭文件類...
我使用的是帶有標(biāo)準(zhǔn) STD 庫(kù)的 Visual Studio 2003.
更新
我想更多地針對(duì)您,因?yàn)槲铱吹酱鸢负芑\統(tǒng),這里我們談?wù)摰氖?std 容器和類型(例如 std::string
)——也許問(wèn)題真的很重要是:
我們能否通過(guò)相同的庫(kù)頭禁用對(duì)客戶端和 DLL 可用的標(biāo)準(zhǔn)容器和類型的警告,并像對(duì)待 int
或任何其他內(nèi)置函數(shù)一樣對(duì)待它們?類型?(它似乎在我這邊工作正常)
如果是這樣,我們應(yīng)該在什么條件下才能做到這一點(diǎn)?
或者是否應(yīng)該禁止使用此類容器,或者至少要格外小心以確保不會(huì)將賦值運(yùn)算符、復(fù)制構(gòu)造函數(shù)等內(nèi)聯(lián)到 DLL 客戶端中?
總的來(lái)說(shuō),我想知道您是否覺得設(shè)計(jì)具有此類對(duì)象的 DLL 接口(例如使用它們將內(nèi)容作為返回值類型返回給客戶端)是否是一個(gè)好主意,以及為什么,我會(huì)喜歡有高水平"此功能的接口...
也許最好的解決方案是 Neil Butterworth 建議的 - 創(chuàng)建一個(gè)靜態(tài)庫(kù)?
當(dāng)您從客戶端訪問(wèn)類中的成員時(shí),您需要提供一個(gè) DLL 接口.DLL 接口意味著編譯器在 DLL 本身中創(chuàng)建函數(shù)并使其可導(dǎo)入.
因?yàn)榫幾g器不知道 DLL_EXPORTED 類的客戶端使用哪些方法,所以它必須強(qiáng)制所有方法都是 dll 導(dǎo)出的.它必須強(qiáng)制客戶端可以訪問(wèn)的所有成員也必須 dll 導(dǎo)出它們的函數(shù).當(dāng)編譯器警告您未導(dǎo)出的方法以及客戶端的鏈接器發(fā)送錯(cuò)誤時(shí),就會(huì)發(fā)生這種情況.
不是每個(gè)成員都必須用 dll-export 標(biāo)記,例如客戶無(wú)法接觸的私人成員.在這里您可以忽略/禁用警告(注意編譯器生成的 dtor/ctors).
否則成員必須導(dǎo)出他們的方法.使用 DLL_EXPORT 向前聲明它們不會(huì)導(dǎo)出這些類的方法.您必須在其編譯單元中將相應(yīng)的類標(biāo)記為 DLL_EXPORT.
它歸結(jié)為...(對(duì)于非 dll 可導(dǎo)出成員)
如果您的成員不能/不能被客戶使用,請(qǐng)關(guān)閉警告.
如果您有必須由客戶端使用的成員,請(qǐng)創(chuàng)建一個(gè) dll 導(dǎo)出包裝器或創(chuàng)建間接方法.
要減少外部可見成員的數(shù)量,請(qǐng)使用PIMPL idiom.
<小時(shí)>
模板類 DLL_EXPORT std::allocator;
這確實(shí)在當(dāng)前編譯單元中創(chuàng)建了模板特化的實(shí)例化.所以這會(huì)在dll中創(chuàng)建std::allocator的方法并導(dǎo)出對(duì)應(yīng)的方法.這不適用于具體類,因?yàn)檫@只是模板類的實(shí)例化.
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.
這篇關(guān)于從 DLL 導(dǎo)出包含 `std::` 對(duì)象(向量、映射等)的類的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!