在模块(exes和dll)之间使用STL(TR1)shared_ptr是否安全?

Aar*_*ark 16 c++ memory-management stl shared-ptr visual-c++

我知道在一个模块中创建新东西并在另一个模块中删除它通常会导致VC++出现问题.运行时间不同的问题.如果我没记错的话,将模块与静态链接的运行时混合和/或动态链接的版本不匹配都可以搞砸了.

但是,跨模块使用VC++ 2008的std :: tr1 :: shared_ptr是否安全?

由于只有一个版本的运行时甚至知道什么是shared_ptr,静态链接是我唯一的危险(现在......).我以为我已经读过boost的版本的shared_ptr可以安全使用,但是我使用的是Redmond的版本......

我试图避免在分配模块中对自由对象进行特殊调用.(或类似于"删除此"本身).如果这一切看起来有点hacky,我正在使用它进行单元测试.如果您曾经尝试对现有的C++代码进行单元测试,那么您可以了解有时需要创造性.我的内存由EXE分配,但最终将在DLL中释放(如果引用计数按我认为的方式工作).

Tim*_*her 14

释放内存是安全的,只要它们来自相同的内存管理上下文.您已经确定了最常见的问题(不同的C++运行时); 拥有单独的堆是另一个不太常见的问题,你可以遇到.

你没有提到但可以通过共享指针进行恶化的另一个问题是当DLL中的对象代码存在并且由DLL创建时,DLL外的另一个对象最终会引用它(通过共享)指针).如果在卸载DLL之后销毁该对象(例如,如果它是模块级静态,或者如果明确卸载DLL FreeLibrary(),则共享对象的析构函数将崩溃.

如果您尝试编写基于DLL的松散耦合插件,这可能会让您感到困惑.这也是COM允许DLL决定何时可以卸载它们的原因,而不是让COM服务器需要卸载它们.


Mar*_*utz 12

你开始看到令人难以置信的惊人shared_ptr:)

跨越DLL边界是安全的,这shared_ptr正是设计的目标(当然,除其他外).

与其他人所说的相反,你甚至不需要在构造时传递自定义删除器shared_ptr,因为默认情况下已经像

template <typename T>
struct default_deleter {
    void operator()( T * t ) { delete t; }
};
Run Code Online (Sandbox Code Playgroud)

shared_ptr<Foo> foo( new Bar );
Run Code Online (Sandbox Code Playgroud)

相当于

shared_ptr<Foo> foo( new Bar, default_deleter<Bar>() );
Run Code Online (Sandbox Code Playgroud)

(即shared_ptr没有删除者就没有这样的东西).

因为在缺失者,则进行的种类擦除delete这就是所谓的将永远是从该DLL的一个实例shared_ptr,从来没有从DLL一个其中最后shared_ptr超出范围(即在shared_ptr调用缺失者将其称之为通过指向由原始文件放置的函数的指针shared_ptr).

与此相比,auto_ptr,其中嵌入了delete直接操作者在其(内联)的析构函数,这意味着delete该DLL的破坏auto_ptr使用,产生同样的问题删除裸指针.

通过相同的技术,总是保存在shared_ptrs中的多态类甚至不需要虚拟析构函数,因为删除器将始终调用正确的析构函数,即使最后一个shared_ptr超出范围是基类的实例化.


Mar*_*som 7

如果您担心,请使用带有删除参数的shared_ptr构造函数的形式.删除器可以回调到分配了对象的模块,以便在适当的上下文中进行删除.

Boost的文档声称它与TR1 100%兼容,所以希望这没有什么误导:

http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/shared_ptr.htm#constructors