【发布时间】:2012-03-21 04:08:53
【问题描述】:
以下程序因 glibc double free 错误而崩溃:
#include <iostream>
#include <memory>
class foo {
public:
foo()
{
std::cout << "foo constructed" << std::endl;
}
~foo()
{
std::cout << "foo destructed" << std::endl;
}
};
int main() {
auto f = std::make_shared< foo >();
std::cout << "Before reset" << std::endl;
f.reset( f.get() );
std::cout << "After reset" << std::endl;
return 0;
}
由此我得到以下输出(后跟 glibc 错误):
foo constructed
Before reset
foo destructed
After reset
foo destructed
很明显,在这种情况下,对象被销毁了两次。一次是重置,一次是std::shared_ptr 超出范围。这实际上是我所期望的。
在cppreference 上,但我发现以下文字(在http://en.cppreference.com/w/cpp/memory/shared_ptr/reset 找到):
如果 *this 已经拥有一个对象并且它是最后一个拥有它的 shared_ptr,则该对象将通过拥有的删除器销毁,除非 ptr 是指向它的指针。
在我看来,这实际上是说,不应像我的示例中那样销毁对象。相当令人惊讶,但如果标准是这样说的。我是否误读了这一点,或者我可用的std::shared_ptr 的实现不符合标准?
对于那些问我为什么要这样做的人:
我目前正试图弄清楚如何临时管理指向由new 和new[] 创建的对象的裸指针。这个想法是使用std::shared_ptr::reset() 将删除器替换为无操作删除器。另一种方法是用 try { stuff() } catch( ... ) { delete x; throw;} 类型的块包装代码。
【问题讨论】:
-
f.reset( f.get() )你为什么曾经想要这样做?如果您有临时的“指向对象的裸指针”,那么您不应该删除它们。你应该只删除你拥有的东西,而不是你从shared_ptr::get获得的东西。 -
@NicolBolas:简单的回答:因为 cppreference 建议这将与其他情况不同的处理方式。好像信息有误。我将在 cppreference 开始对此进行讨论。
-
这只是解释了为什么你认为它会起作用。这并不能解释为什么你认为这是一个好主意,不管它是否有效。你想做什么你需要这个?
-
@NicolBolas:通过替换删除器从
std::shared_ptr释放指针。但是,这实际上确实可以与std::unique_ptr一起正常工作,我现在也可以使用它。 -
@NicolBolas:实际部分是这样的:试图为当前问题找到一个好的设计,查看 cppreference,发现一些我不太相信的东西,所以我尝试了它。现在我想弄清楚谁是错的,谁是对的。
标签: c++ c++11 shared-ptr