在dll之间传递shared_ptr和其他STL是否安全?因此,如果使用相同的编译器和兼容的编译器标志来构建,则也是如此?

问题描述

我看到一些文章指出,由于在dll之间传递STL和shared_ptr是不安全的,

  1. 可能导致内存损坏和
  2. 它们可能具有不同的C ++运行时实现,因此会导致未定义的行为。

问题1:如果我使用相同的编译器版本和标志来编译两个库,这是真的吗?考虑到C ++运行时是相同的,并且通常从调用进程的虚拟地址空间为dll分配内存,而这两点仍然有效。

问题2:我看到的解决方案涉及在堆上的一个dll中创建对象,并传递一个自定义析构函数,该析构函数在smart_ptr创建时将其清除并传递,以便可以从创建它的第二个第一个dll中安全地删除它当参考丢失时。什么时候需要?这不是ABI稳定的吗?这不是仅需要dll在其自己的地址空间中创建对象,并且您不希望其他dll从其中删除吗?那不是认值吗?

问题3:这是否与使用不同编译器版本构建的静态库相互交谈一样?

解决方法

在dll之间使用std库类型是一个具体的实际问题。

相同的标准库,两个dll。

Dll1定义了一个Foo类。

Dll2将Foo包装在共享的ptr中。在Dll2中使用cose类型擦除了Foo的销毁代码。

Dll2已卸载。

对共享ptr的最后引用消失了。

程序崩溃。

现在,我已解决此问题;您需要真正关心在何处创建共享的ptrs。如果您具有执行此操作的代码(例如,写指针上的副本),则每次创建新的ptr时,都必须调用Dll1以获得新的共享ptrs。

话虽如此,我们仍然这样做。我只是说这不是免费的。即使我自己重新实现了共享ptr,也会发生同样的问题。这是代码产生问题的代码,该代码可以动态生成代码(即带有rype擦除的模板)并将其附加到多dll环境中的值。

,

(1-2)DLL具有单独的堆。因此,在一个dll中分配内存并在另一个dll中释放内存会导致崩溃。这不仅是一个shared_ptr或STL的问题,而且是一个非常普遍的问题,并且带来很多困难。 shared_ptr可用于解决此问题:在shared_ptr中,您可以指定在正确的dll中调用delete的deleter函数。

(3)当您将库链接在一起时,尤其是作为静态库时,不同的编译器版本可能会导致严重的问题。想象一下STL中的一些实现差异。它很容易导致崩溃或代码损坏。例如,在MSVC中,将debug与r​​elease链接可能会导致std::string崩溃。 MSVC的警告之一是在使用原子时-他们说在VS2015中,某些类型的atmics中存在错误,因此请不要与该版本VS的库链接。

要安全地链接不同的编译器/版本,必须有dll。通常,人们会尝试在DLL中实现一个非常基本的接口,以便它尽可能安全地使用ABI。