关于c ++:如何在DLL边界上公开STL列表?

How to expose STL list over DLL boundary?

我有一个DLL,它需要访问存储在宿主应用程序的STL容器中的数据。因为C++没有标准的ABI,并且我想支持不同的编译器,所以应用程序和DLL之间的接口基本上必须保持原始的旧数据。

对于向量,这是相对简单的。您只需返回向量的内存块,因为它保证是不符合条件的:

1
2
3
4
5
6
7
8
// To return vector<int> data
virtual void GetVectorData(const int*& ptr, size_t& count) const
{
    if (!vec.empty())
        ptr = &(vec.front());

    count = vec.size();
}

现在,DLL可以通过该接口安全地以只读方式访问向量的数据。动态链接库也可以将其包装,以便将内容复制到向量中。

但是STL列表(和Deques)呢?是否有另一种简单的方法允许通过DLL边界进行访问?或者我必须使用某种getfirst()/getnext()接口?我可能需要为很多列表做这个,所以最好有一个像向量这样简单的解决方案。


如果在实例化每个STL类型时很小心,则可以在DLL之间传递STL对象并支持不同的编译器。您需要一些智能的"dllexport"宏——我使用下面的集合成功地支持vc和gcc。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifdef WIN32
#ifdef MYDLLLIB_EXPORTS      // DLL export macros
#define MYDLLLIB_API __declspec(dllexport)
#define MYDLLLIB_TEMPLATE
#else
#define MYDLLLIB_API __declspec(dllimport)
#define MYDLLLIB_TEMPLATE extern
#endif
#else                       // Not windows --- probably *nix/bsd
#define MYDLLLIB_API
#ifdef MYDLLLIB_EXPORTS
#define MYDLLLIB_TEMPLATE
#else
#define MYDLLLIB_TEMPLATE extern
#endif
#endif // WIN32

编译dll时,请定义mydlllib_exports。在DLL中,您可以实例化您想要使用的每个STL类型,例如,字符串的列表或向量。

1
2
MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::vector<std::string>;
MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::list<std::string>;

然后,您的dll的使用者(没有定义mydlllib_导出)将看到

1
extern template class __declspec(dllimport) std::vector<std::string>;

并使用从DLL中导出的二进制代码,而不是实例化它们自己的代码。


也许您可以将类似"handles"的东西传递给list/deque迭代器?这些句柄类型将是不透明的,并在将发送给用户的头文件中声明。在内部,您需要将句柄值映射到list/deque迭代器。基本上,用户编写的代码如下:

1
2
3
4
5
6
7
8
9
ListHandle lhi = GetListDataBegin();
const ListHandle lhe = GetListDataEnd();

while (lhi != lhe)
{
  int value = GetListItem(lhi);
  ...
  lhi = GetNextListItem(lhi);
}


the interface between the application
and DLL basically has to remain
plain-old-data.

不一定。您必须确保使用相同的编译器版本。此外,影响STL对象布局的构建设置在DLL和应用程序之间完全相同。

如果您要将DLL释放到野外,那么您就应该关心跨DLL边界公开STL。但是,如果一切都在您的控制之下,并且完全是内部的(或者如果您可以严格地执行第三方构建设置/编译器),那么您就可以了。