【问题标题】:What happens if I reset a std::shared_ptr to itself如果我将 std::shared_ptr 重置为自身会发生什么
【发布时间】: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 的实现不符合标准?

对于那些问我为什么要这样做的人:

我目前正试图弄清楚如何临时管理指向由newnew[] 创建的对象的裸指针。这个想法是使用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


【解决方案1】:

reset 重载的规范在 20.7.2.2.4 shared_ptr 修饰符 [util.smartptr.shared.mod] 第 3 段(来自 n3290)中给出:

template<class Y> void reset(Y* p);

效果:相当于shared_ptr(p).swap(*this)

如您所见,shared_ptr(p) 构造为 p 创建了一个带有新删除器的新计数,因此不会有任何好处。将std::shared_ptr&lt;T&gt;::get 视为严格的观察者确实是最好的,用它来处理生命周期管理是一个迹象,表明有问题正在发生。

另一方面,std::unique_ptr&lt;T&gt; 具有release,这正是您需要介入并自己处理所有权的瞬间。也许您可以更改您的设计以使用std::unique_ptr&lt;T&gt;?如果您最终需要,始终可以从中创建一个std::shared_ptr&lt;T&gt;。 (虽然std::shared_ptr&lt;T&gt;std::unique_ptr&lt;T&gt; 中选择删除器,但您仍然需要在数组情况下进行特殊处理,因为您可能希望std::shared_ptr&lt;T*&gt; 来自std::unique_ptr&lt;T[]&gt;。)

【讨论】:

  • 好的,如果我没有看到 cppreference 上的定义,这就是我所期望的。我将在那里开始讨论以更改它。
猜你喜欢
  • 1970-01-01
  • 2010-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-11
  • 1970-01-01
  • 2020-09-25
  • 2011-08-06
相关资源
最近更新 更多