在跨DLL边界使用std::move是一个好的实践吗?

4

任何在Windows上使用DLL的人都会告诉你,在DLL边界的一侧使用new创建一个对象,然后在另一侧使用delete删除它是个坏主意。通常,为了避免这种情况发生,我们会在DLL中使用工厂方法来创建对象,以便执行新/删除的对象代码位于同一对象文件中。

今天,我正在设计一个新的接口,我想从一个对象中std::move一个std::vector<std::wstring>到另一个对象,其中这些对象是在不同的DLL中创建的。当我准备好执行此操作时,我突然想到,由于另一个对象现在拥有底层指针,这可能意味着delete现在可能会在不同的对象代码中发生,与new所在的代码不同。

有人能否确认这是否是真的?


3
对于“移动”操作和“交换”操作,应该考虑的因素是相同的。 - Steve Jessop
1
更加通用的说法是:STL对象不应该跨越DLL边界传递。因此,即使不使用std::move,整个解决方案也存在缺陷。 - Alex F
1
@AlexFarber 我在导出的类规则中找不到关于标准对象(如std::vector)的任何内容,如果你在某个地方看到了,请发一个链接好吗? - Benj
1
在dll可执行文件中创建的STL对象不应直接从另一个exe/dll中访问 - 只能通过创建它的dll的函数访问。STL对象可能是实现的一部分,但不是接口。 - Alex F
1
@AlexFarber:这适用于公共接口。如果您的Foo应用程序有一个“FooPrint.DLL”,当用户想要打印某些内容时,该DLL将被延迟加载,那么使用STL是可以的。您提到的KB文章适用于Visual Studio 6及更早版本。那已经是14年前的事了! - MSalters
显示剩余4条评论
1个回答

4

通常,只有析构函数(以及复制构造函数/赋值函数)不做太多操作的对象才应跨越DLL边界。最好只使用POD以实现最大安全性(从而允许两个DLL进行接口,即使它们没有用完全相同的编译器版本进行编译)。

关于移动时会发生什么,是的,接收端DLL将释放提供DLL分配的内存。这通常属于“不好”的类别。

如果您想使其更加安全,可以使用特殊的分配器来从接收DLL分配(和释放)内存。但这通常很麻烦。


1
仅当 DLL 可以使用不同的编译器、设置和/或标准库编译时返回 True。 - MSalters
移动智能指针(如unique_ptr或shared_ptr)有什么不同吗?还是它们完全相同? - Johan Lundberg
1
@Johan:这些可以工作,但只有在它们上面有显式析构函数并调用正确的 DLL 时才能工作。 - Nicol Bolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接