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。但是,如果一切都在您的控制之下,并且完全是内部的(或者如果您可以严格地执行第三方构建设置/编译器),那么您就可以了。