我可以将 std::string 传递给 DLL 吗?
Posted
技术标签:
【中文标题】我可以将 std::string 传递给 DLL 吗?【英文标题】:Can I pass std::string to a DLL? 【发布时间】:2011-07-17 20:51:58 【问题描述】:我将一个代码片段分成DLL
,因为它会经常更新,这样应该更容易部署。
但我对 DLL
能做什么和不能做什么有疑问。
-
我可以将
std:string
或CString
传递给DLL
吗?
我可以用std::string members
传递指向struct
的指针并将其填入DLL
吗?
DLL
可以返回指向分配在那里的结构的指针吗?会有效吗?之后可以删除吗?
最好传递什么,std::String
或 Cstring
?
谢谢!
【问题讨论】:
【参考方案1】:您可以选择:
紧耦合 DLL:该 DLL 使用与应用程序完全相同的编译器版本、打包和调用约定设置、库选项构建,并且都动态链接到运行时库(/MD
编译器选项)。这使您可以来回传递对象,包括 STL 容器,从应用程序内部分配 DLL 对象,从其他模块中的基类派生,在不使用 DLL 的情况下做几乎所有可以做的事情。缺点是您不能再独立于主应用程序部署 DLL。两者必须一起建造。 DLL 只是为了改善您的进程启动时间和工作集,因为应用程序可以在加载 DLL 之前开始运行(使用 /delayload
链接器选项)。构建时间也比单个模块快,尤其是在使用整个程序优化时。但优化不会跨应用程序-DLL 边界进行。任何重要的更改仍然需要重建两者。
松散耦合:应用程序不依赖于 DLL 定义的对象的类布局。您只使用高度兼容的数据类型:原始类型、指针、函数指针和由这些元素组成的用户定义类型。类从定义接口的基类继承,没有数据成员和非虚拟函数(这意味着没有构造函数,也没有共享标准库对象,例如std::string
或CString
)。所有分配和对象创建都必须通过工厂函数完成。必须从分配它的模块中释放内存。代码和数据是分开的。头文件明确说明了每个导出函数的调用约定和允许跨模块边界的每个结构的打包。优点是DLL和应用程序可以完全独立更新。您可以使用新的运行时库、新的编译器版本,甚至是全新的语言重新构建一个,而无需再接触另一个。
我总是建议使用松散耦合的方法。
【讨论】:
@bratao:您无法从主应用程序中删除 DLL 中分配的内存。并且DLL可以使用std::string
,但在应用程序中与std::string
不同。您不能在应用程序和 DLL 之间传递 std::string
,而是按照 Mark 的建议传递 char*
。
@Ela782:作用域资源管理类不能安全地跨越边界。您可以在客户端使用它们来管理跨边界传递的原始指针(确保设置一个调用正确释放函数的自定义删除器,默认删除器在这种情况下不起作用),但是智能指针物体不能交叉。
@Ela782:您必须查看保证的详细信息,但我认为这不会使情况明显好转。 ABI 兼容性意味着如果您的原始类型聚合不更改定义,您可以将那些特定的编译器版本视为满足“完全相同的编译器版本”要求。但是namespace std
中的类定义仍然会发生变化(它们必须改变,因为 C++ 标准委员会改变了要求),所以这些仍然不能跨模块边界使用。
听起来你决心要靠运气而不是采用稳健的方法。即使您在来自同一编译器供应商的某些版本之间具有完全的 ABI 兼容性和库不变性,我仍然会认为这是紧密耦合的,因为您剥夺了 DLL 消费者对编译器的选择。
Hm.. OpenCV 为何将std::string&
作为其某些公共函数的参数(imwrite、imread、cv::String
是std::string
的类型定义)?他们不能错过它【参考方案2】:
如果将任何内容传入和传出 DLL,则如果它基于模板,则存在危险。编译器选项会影响对象的布局,一个模板类不能局限于单个编译单元;其中一些将分发给调用模块。
在字符串的情况下,我会传递一个const char *
(或const wchar_t *
或const TCHAR *
)并在接口的另一侧,在DLL中转换为std::string
或CString
.
【讨论】:
不仅仅是模板,任何具有内联成员函数的类都会创建布局依赖。 @Ben,确实如此。但是根据定义,模板是内联的,因此警告对它们来说是双重的。 谢谢你的想法,我会做的!以上是关于我可以将 std::string 传递给 DLL 吗?的主要内容,如果未能解决你的问题,请参考以下文章
C ++通过引用dll中的函数传递std :: string
从 C++/CLI 应用程序将 STL 字符串传递给 C++ DLL
为啥这个程序会崩溃:在 DLL 之间传递 std::string