問題描述
在 dll 接口中使用 stl 類不是一個好習慣,如 處理警告 c4251 的常見做法:class ...需要有 dll-interface 解釋.給出一個例子:
#include #include <字符串>#include <向量>類 __declspec(dllexport) HelloWorld{上市:你好世界(){abc.resize(5);for(int i=0; i<5; i++)abc[i] = i*10;str="你好世界";}?你好世界(){}std::vectorABC;std::string str;};
編譯此文件時,可以觀察到以下警告:
警告 C4251: 'HelloWorld::str' : class 'std::basic_string<_Elem,_Traits,_Ax>'需要有 dll 接口供HelloWorld"類的客戶端使用警告 C4251:HelloWorld::abc":類std::vector<_Ty>"需要有 dll 接口供HelloWorld"類的客戶端使用
那么問題是我們如何在不使用 STL 類向量和字符串的情況下實現相同的功能.我能想到的一種實現如下:
class __declspec(dllexport) HelloWorld2{上市:你好世界2(){abc_len = 5;p_abc = new int [abc_len];for(int i=0; i<abc_len; i++)p_abc[i] = i*10;std::string temp_str("hello_the_world");str_len = temp_str.size();p_str = 新字符[str_len+1];strcpy(p_str,temp_str.c_str());}~HelloWorld2(){刪除 []p_abc;刪除 []p_str;}int *p_abc;國際 abc_len;字符 *p_str;int str_len;};
如您所見,在新的實現中,我們使用 int *p_abc 替換向量 abc 和 char *p_str 替換字符串 str.我的問題是是否有其他優雅的實現方法可以做到這一點.謝謝!
我認為您至少有 5 種可能的選擇來解決這個問題:
您仍然可以為您的字段保留 STL/模板類,也可以將它們用作參數類型,只要您將所有字段保持為私有(無論如何這都是一個很好的做法).這里是關于這個的討論.要刪除警告,您可以簡單地根據
#pragma
語句使用.您可以創建帶有私有 STL 字段的小型包裝類,并將您的包裝類類型的字段公開給公眾,但這很可能只會將警告移到其他地方.
您可以使用 PIMPL 習語來隱藏您的私有實現類中的 STL 字段,它甚至不會從您的庫中導出,也不會在庫外可見.
或者您實際上可以按照 C4251 警告中的建議,以此處.簡而言之,您必須在
HelloWorld
類之前插入以下代碼行:<代碼>...#include <向量>模板類 __declspec(dllexport) std::allocator
;模板類 __declspec(dllexport) std::vector ;模板類 __declspec(dllexport) std::string;類 __declspec(dllexport) HelloWorld... 順便說一下,這些導出的順序似乎很重要:向量類模板在內部使用分配器類模板,因此必須在向量實例化之前導出分配器實例化.p>
直接使用內部函數可能是您最糟糕的選擇,但如果您封裝字段
int *p_abc;國際 abc_len;
在類似
class MyFancyDataArray
和字段char *p_str;int str_len;
在類似
class MyFancyString
的東西中,那么這將是一個更體面的解決方案(類似于第二點描述的解決方案).但過于頻繁地重新發明輪子可能不是最好的習慣.
It is not a good practice using stl-classes in the dll-interface as Common practice in dealing with warning c4251: class … needs to have dll-interface explains. An example is given:
#include <iostream>
#include <string>
#include <vector>
class __declspec(dllexport) HelloWorld
{
public:
HelloWorld()
{
abc.resize(5);
for(int i=0; i<5; i++)
abc[i] = i*10;
str="hello the world";
}
~HelloWorld()
{
}
std::vector<int> abc;
std::string str;
};
When compiling this file, the following warnings can be observed:
warning C4251: 'HelloWorld::str' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'HelloWorld'
warning C4251: 'HelloWorld::abc' : class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'HelloWorld'
Then the question is how we can implement the same functionality without using STL class vector and string. One implementation I could think of is as follows:
class __declspec(dllexport) HelloWorld2
{
public:
HelloWorld2()
{
abc_len = 5;
p_abc = new int [abc_len];
for(int i=0; i<abc_len; i++)
p_abc[i] = i*10;
std::string temp_str("hello_the_world");
str_len = temp_str.size();
p_str = new char[str_len+1];
strcpy(p_str,temp_str.c_str());
}
~HelloWorld2()
{
delete []p_abc;
delete []p_str;
}
int *p_abc;
int abc_len;
char *p_str;
int str_len;
};
As you can see, in the new implementation we use int *p_abc to substitute vector abc and char *p_str to replace string str. The question I have is whether there are other elegant implementation approaches that can do the same. Thanks!
I think you've got at least 5 possible options to solve this problem:
You could still keep STL/template classes for your fields and also use them as parameter types, as long as you keep all the fields private (which is a good practice anyway). Here is a discussion about this. To remove the warnings you could simply use according
#pragma
statements.You could create small wrapper classes with private STL fields and expose fields of your wrapper class types to the public instead, but this would most probably only move the warnings to another places.
You could use the PIMPL idiom to hide your STL fields in a private implementation class, which will not even be exported from your library nor be visible outside of it.
Or you could actually export all the required template class specializations, as suggested in the C4251 warning, in a way that is described here. In short you would have to insert following lines of code before your
HelloWorld
class:... #include <vector> template class __declspec(dllexport) std::allocator<int>; template class __declspec(dllexport) std::vector<int>; template class __declspec(dllexport) std::string; class __declspec(dllexport) HelloWorld ...
By the way, the order of those exports seems to be important: the vector class template uses the allocator class template internally, so the allocator instantiation has to be exported before the vector instantiation.
The direct use of intrinsics is probably your worst option, but if you encapsulate your fields
int *p_abc; int abc_len;
in something like
class MyFancyDataArray
and the fieldschar *p_str; int str_len;
in something like
class MyFancyString
, then this would be a more decent solution (similar to the one described at the second point). But it is probably not the best habit to reinvent the wheel too often.
這篇關于在 dll 接口中使用 stl 類時消除 C4251 警告的一種方法的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!