fee*_*ree 20 c++ visual-studio-2010
在dll-interface中使用stl-classes作为处理警告c4251的常用做法不是一个好习惯:class ...需要有dll-interface解释.给出了一个例子:
#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;
};
Run Code Online (Sandbox Code Playgroud)
编译此文件时,可以观察到以下警告:
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'
Run Code Online (Sandbox Code Playgroud)
那么问题是我们如何在不使用STL类向量和字符串的情况下实现相同的功能.我能想到的一个实现如下:
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;
};
Run Code Online (Sandbox Code Playgroud)
如您所见,在新实现中,我们使用int*p_abc替换向量abc和char*p_str来替换字符串str.我的问题是,是否有其他优雅的实现方法可以做同样的事情.谢谢!
buy*_*ush 25
我认为你至少有5个可能的选择来解决这个问题:
您仍然可以保留字段的STL /模板类,并将它们用作参数类型,只要您将所有字段保密(这无论如何都是一个好的做法).这是对此的讨论.要删除警告,您只需使用相应的#pragma语句即可.
您可以使用私有STL字段创建小包装类,并将包装类类型的字段公开给公众,但这很可能只会将警告移动到其他位置.
您可以使用PIMPL惯用法在私有实现类中隐藏您的STL字段,这些字段甚至不会从您的库中导出,也不会在其外部可见.
或者,您可以按照此处描述的方式实际导出所有必需的模板类特化,如C4251警告中所述.简而言之,您必须在HelloWorld课程之前插入以下代码行:
...
#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
...
Run Code Online (Sandbox Code Playgroud)
顺便说一下,这些导出的顺序似乎很重要:向量类模板在内部使用allocator类模板,因此必须在向量实例化之前导出allocator实例化.
直接使用内在函数可能是你最糟糕的选择,但如果你封装了你的字段
int *p_abc;
int abc_len;
Run Code Online (Sandbox Code Playgroud)
在类似的东西class MyFancyDataArray和领域
char *p_str;
int str_len;
Run Code Online (Sandbox Code Playgroud)
在类似的东西class MyFancyString,那么这将是一个更体面的解决方案(类似于第二点描述的解决方案).但这可能不是经常重新发明轮子的最佳习惯.
或做最简单的事情,移动__declspec到您想要导出的ONLY成员:
class HelloWorld
{
public:
__declspec(dllexport) HelloWorld()
{
abc.resize(5);
for(int i=0; i<5; i++)
abc[i] = i*10;
str="hello the world";
}
__declspec(dllexport) ~HelloWorld()
{
}
std::vector<int> abc;
std::string str;
};
Run Code Online (Sandbox Code Playgroud)
我不确定你想在这里解决哪个问题.有两个不同的问题:交叉编译器二进制兼容性和避免"未定义符号"链接器错误.你引用的C4251警告谈到了第二个问题.这实际上是一个非问题,尤其是SCL类std::string和std::vector.由于它们是在CRT中实现的,只要应用程序的两端都使用相同的CRT,一切都将"正常工作".在这种情况下的解决方案是只禁用警告.
交叉编译二进制兼容性OTOH,这是你链接的其他stackoverflow问题中讨论的,是一个完全不同的野兽.为了解决这个问题,你基本上必须保留所有公共头文件,不要提及任何SCL类.这意味着您要么必须使用PIMPL,要么在任何地方使用抽象类(或者混合使用).
| 归档时间: |
|
| 查看次数: |
25689 次 |
| 最近记录: |