简体   繁体   English

如果我将std :: shared_ptr重置为自身会发生什么

[英]What happens if I reset a std::shared_ptr to itself

The following program crashes with a bad glibc double free error: 以下程序崩溃时出现错误的glibc双重自由错误:

#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;
}

From this I get the following output (followed by the glibc error): 从这里我得到以下输出(后跟glibc错误):

foo constructed
Before reset
foo destructed
After reset
foo destructed

So obviously in this case the object is destroyed twice. 很明显,在这种情况下,对象被销毁两次。 Once by the reset and once by the std::shared_ptr going out of scope. 一旦通过重置,一次由std::shared_ptr超出范围。 This is actually what I would have expected. 这实际上是我所期待的。

On cppreference however I find the following text (found at http://en.cppreference.com/w/cpp/memory/shared_ptr/reset ): 但是在cppreference上我找到了以下文本(可在http://en.cppreference.com/w/cpp/memory/shared_ptr/reset找到):

If *this already owns an object and it is the last shared_ptr owning it, the object is destroyed through the owned deleter, unless ptr is a pointer to it. 如果*这已经拥有一个对象并且它是拥有它的最后一个shared_ptr,则该对象将通过拥有的删除器销毁,除非ptr是指向它的指针。

In my opinion this actually says, that the object should not be destroyed as in my example. 在我看来,这实际上说,对象不应该像我的例子那样被销毁。 Quite surprising, but if the standard says so. 相当令人惊讶,但如果标准这样说。 Am I somehow misreading this, or is the implementation of std::shared_ptr I have available not conforming to the standard? 我在某种程度上误读了这个,或者是std::shared_ptr的实现我有可能不符合标准吗?

For those who ask why I am doing this: 对于那些问我为什么这样做的人:

I am currently trying to figure out how to temporarily manage bare pointers to objects created by new and new[] . 我目前正在试图弄清楚如何临时管理由newnew[]创建的对象的裸指针。 The idea is to use the std::shared_ptr::reset() to replace the deleter with a no-op deleter. 我们的想法是使用std::shared_ptr::reset()将删除器替换为no-op删除器。 The alternative is to wrap the code with a try { stuff() } catch( ... ) { delete x; throw;} 另一种方法是使用try { stuff() } catch( ... ) { delete x; throw;} try { stuff() } catch( ... ) { delete x; throw;} kind of block. try { stuff() } catch( ... ) { delete x; throw;}种块。

The specification for that overload of reset is given in 20.7.2.2.4 shared_ptr modifiers [util.smartptr.shared.mod], paragraph 3 (from n3290): reset过载的规范在20.7.2.2.4 shared_ptr修饰符[util.smartptr.shared.mod],第3段(来自n3290)中给出:

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

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

As you can see, that shared_ptr(p) construction creates a new count with new deleter for that p , so nothing good can come off it. 正如你所看到的, shared_ptr(p)建设创建与新缺失者一个新的数p ,所以没有什么好可以摘下来了。 It really is the best to think of std::shared_ptr<T>::get as strictly an observer, and using it to deal with lifetime management is a telltale sign that there is something wrong going on. 最好将std::shared_ptr<T>::get视为一个严格的观察者,并使用它来处理生命周期管理是一个迹象表明存在错误。

On the other hand, std::unique_ptr<T> has release , which is exactly what you need when you need to step in and deal with ownership yourself for an instant. 另一方面, std::unique_ptr<T>已经release ,这正是您需要介入并立即处理所有权时所需要的。 Perhaps you can change your design to use std::unique_ptr<T> ? 也许您可以将设计更改为使用std::unique_ptr<T> It's always possible to create a std::shared_ptr<T> out of it if you need to, eventually. 如果需要,最终可以从中创建一个std::shared_ptr<T> (Although while the std::shared_ptr<T> picks the deleter from the std::unique_ptr<T> , you still need special treatment in the array case as you probably want std::shared_ptr<T*> from std::unique_ptr<T[]> .) (虽然当std::shared_ptr<T>std::unique_ptr<T> std::shared_ptr<T>选择删除器时,你仍然需要在数组的情况下进行特殊处理,因为你可能需要来自std::unique_ptr<T[]> std::shared_ptr<T*> std::unique_ptr<T[]> 。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM