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

C++ 在dll导出函数中使用std::vector的含义,c++,dll,stl,C++,Dll,Stl,我有两个dll导出类A和B。A的声明包含一个函数,该函数在其签名中使用std::vector,如: class EXPORT A{ // ... std::vector<B> myFunction(std::vector<B> const &input); }; 类导出A{ // ... std::vector myFunction(std::vector const&input); }; (导出是相应地放置_declspec(dllexport)/_de

我有两个dll导出类A和B。A的声明包含一个函数,该函数在其签名中使用std::vector,如:

class EXPORT A{
 // ...
 std::vector<B> myFunction(std::vector<B> const &input);
};
类导出A{
// ...
std::vector myFunction(std::vector const&input);
};
(导出是相应地放置_declspec(dllexport)/_declspec(dllimport)的常用宏。)

通过阅读与在DLL接口中使用STL类相关的问题,我总结如下:

  • 在DLL接口中使用std::vector将要求该DLL的所有客户端使用同一编译器的同一版本进行编译,因为STL容器不是二进制兼容的。更糟糕的是,根据客户端与其他DLL联合使用该DLL,“不稳定”DLL API可能会在安装系统更新(例如Microsoft KB软件包)时破坏这些客户端应用程序(真的吗?)

  • 尽管有上述规定,如果需要,std::vector可以通过导出
    std::vector
    在DLL API中使用,如:

    template class EXPORT std::allocator<B>;
    template class EXPORT std::vector<B>;
    
    模板类导出std::分配器;
    
    模板类导出std::vector;
    不过,当您想将std::vector用作(http://support.microsoft.com/kb/168958)

  • 下面的Microsoft Support文章讨论了如何通过可执行文件中的指针或引用访问在DLL中创建的std::vector对象(http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q172396)。上面使用
    模板类导出的解决方案…
    似乎也适用。然而,在第一个要点下总结的缺点似乎仍然存在

  • 为了彻底解决这个问题,需要包装std::vector并更改
    myFunction
    、PIMPL等的签名

我的问题是:

  • 上面的总结是正确的,还是我遗漏了一些重要的东西

  • 为什么我的类“A”的编译不会生成警告C4251(类“std::vector”需要有dll接口才能由…的客户端使用?我没有关闭编译器警告,也没有在导出的类A(使用VS2005)中使用
    myFunction
    中的std::vector得到任何警告

  • 需要做些什么才能正确地在一个数据库中导出
    myFunction
    ?只导出
    std::vector
    和B的分配器是否可行

  • 按值返回std::vector的含义是什么?假设客户机可执行文件已使用不同的编译器(-version)编译。当按复制向量的值返回时,问题是否仍然存在?我想是的。类似地,将std::vector作为常量引用传递:访问
    std::vector
    (可能由使用不同编译器(-version)编译的可执行文件构造)是否会导致
    myFunction
    中出现问题?我想是的

  • 上面列出的最后一点真的是唯一干净的解决方案吗


非常感谢您的反馈。

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

编译器将其所能映射到特定操作系统中DLL导入和导出的方式。由于语言规范为编译器提供了很大的自由,当涉及到用户定义类型的二进制布局时,有时甚至是内置类型(回想一下,
int
的确切大小取决于编译器,只要满足最小的大小要求),从DLL导入和导出需要手动完成,以实现二进制级别的兼容性


当您使用同一编译器的同一版本时,上述最后一个问题不会产生问题。然而,一旦出现不同的编译器,所有的赌注都将落空:您需要返回到简单类型的接口,并引入包装器以在代码中维护美观的接口。

我也遇到了同样的问题,并找到了一个简洁的解决方案。
您可以从
Qt
库中传递
QVector
,而不是传递
std:vector

然后,您引用的问题将在
Qt
库中处理,您根本不需要处理它。
当然,成本是必须使用库并接受其稍差的性能。

就它为您节省的编码和调试时间而言,这个解决方案非常值得。

Mmmh。。但如果我用
int
替换
std::vector
,这意味着同样的问题也会存在?或者,操作系统能够映射类型到什么程度?@user1043103在我上一次的C工作中,我们有编码标准,只要求在从DLL导出的函数签名中使用
#定义
-d类型,避免使用内置原语。例如,我们应该使用而不是
int
——大概是为了保持编译器不同版本之间的兼容性;用于正确导出/导入所有成员函数。那些不是成员函数的模板函数呢?例如,运算符==()?从VS 2012开始,我现在在构建DLL时出现链接错误,因为向量比较函数未定义。建议相关阅读: