在dll导出函数中使用std :: vector的含义

时间:2012-05-13 15:58:41

标签: c++ dll stl

我有两个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内的问题?我想再说一遍......

  • 上面列出的最后一个要点是否真的是唯一干净的解决方案?

非常感谢您的反馈。

2 个答案:

答案 0 :(得分:2)

不幸的是,你的清单非常有用。其根本原因是DLL-to-DLL或DLL-to-EXE是在操作系统级别定义的,而函数之间的接口是在编译器级别定义的。在某种程度上,当客户端和服务器缺乏二进制兼容性时,您的任务与客户端 - 服务器交互的任务类似(尽管有些简单)。

编译器将它可以映射到DLL导入和导出在特定操作系统中完成的方式。由于语言规范为编译器提供了很多自由,因为它涉及用户定义类型的二进制布局,有时甚至是内置类型(回想一下,int的确切大小是编译器相关的,只要最小化大小要求如果遇到这种情况,需要手动完成从DLL导入和导出,以实现二进制级兼容性。

当您使用相同版本的相同编译器时,上面的上一个问题不会产生问题。然而,只要不同的编译器进入图片,所有的赌注都会关闭:你需要回到明显类型的接口,并引入包装器来维护代码中漂亮的接口。

答案 1 :(得分:0)

我遇到了同样的问题并发现了一个简洁的解决方案 您可以从std:vector库中传递QVector,而不是传递Qt 然后,您引用的问题将在Qt库中处理,您根本不需要处理它 当然,成本是必须使用库并接受其稍差的性能 就节省的编码和调试时间而言,这个解决方案非常值得。