我有两个dll导出的类A和B.A的声明包含一个在其签名中使用std :: vector的函数,如:
class EXPORT A{
// ...
std::vector<B> myFunction(std::vector<B> const &input);
};
(EXPORT是相应的通常的宏_ declspec(dllexport)/ _declspec(dllimport)。)
阅读有关在DLL接口中使用STL类的相关问题,我总结一下:
在DLL接口中使用std :: vector将需要使用相同编译器的相同版本编译该DLL的所有客户端,因为STL容器不是二进制兼容的。更糟糕的是,取决于客户端与其他DLL一起使用该DLL,''不稳定''DLL API可以在安装系统更新时破坏这些客户端应用程序(例如Microsoft KB软件包)(真的吗?)。
尽管如此,如果需要,可以通过导出std::vector<B>
来在DLL API中使用std :: vector,如:
template class EXPORT std::allocator<B>;
template class EXPORT std::vector<B>;
但是,当人们想要将std :: vector用作A的成员(http://support.microsoft.com/kb/168958)时,通常会在上下文中提到这一点。 / p>
以下Microsoft支持文章讨论了如何通过可执行文件中的指针或引用访问DLL中创建的std :: vector对象(http://support.microsoft.com/default.aspx?scid= KB; EN-US; Q172396)。上述使用template class EXPORT ...
的解决方案似乎也适用。但是,在第一个要点下总结的缺点似乎仍然存在。
要完全摆脱这个问题,需要包装std :: vector并更改myFunction
,PIMPL等的签名。
我的问题是:
上述摘要是正确的,还是我在这里想念一些必要的内容?
为什么我的类'A'的编译没有生成警告C4251(类'std :: vector&lt; _Ty&gt;'需要让dll-interface被...的客户端使用)?我没有关闭编译器警告,在导出的A类(使用VS2005)myFunction
中使用std :: vector时没有任何警告。
在A中正确导出myFunction
需要做些什么?仅导出std::vector<B>
和B的分配器是否可行?
返回std :: vector by-value有什么含义?假设客户端可执行文件已使用不同的编译器(-version)编译。在复制向量的情况下返回by-value时是否仍然存在问题?我猜是。类似地,将std :: vector作为常量引用传递:可以访问std::vector<B>
(可能由使用不同编译器(-version)编译的可执行文件构造)导致myFunction
内的问题?我想再说一遍......
上面列出的最后一个要点是否真的是唯一干净的解决方案?
非常感谢您的反馈。
答案 0 :(得分:2)
不幸的是,你的清单非常有用。其根本原因是DLL-to-DLL或DLL-to-EXE是在操作系统级别定义的,而函数之间的接口是在编译器级别定义的。在某种程度上,当客户端和服务器缺乏二进制兼容性时,您的任务与客户端 - 服务器交互的任务类似(尽管有些简单)。
编译器将它可以映射到DLL导入和导出在特定操作系统中完成的方式。由于语言规范为编译器提供了很多自由,因为它涉及用户定义类型的二进制布局,有时甚至是内置类型(回想一下,int
的确切大小是编译器相关的,只要最小化大小要求如果遇到这种情况,需要手动完成从DLL导入和导出,以实现二进制级兼容性。
当您使用相同版本的相同编译器时,上面的上一个问题不会产生问题。然而,只要不同的编译器进入图片,所有的赌注都会关闭:你需要回到明显类型的接口,并引入包装器来维护代码中漂亮的接口。
答案 1 :(得分:0)
我遇到了同样的问题并发现了一个简洁的解决方案
您可以从std:vector
库中传递QVector
,而不是传递Qt
然后,您引用的问题将在Qt
库中处理,您根本不需要处理它
当然,成本是必须使用库并接受其稍差的性能
就节省的编码和调试时间而言,这个解决方案非常值得。