What happens if I reset a std::shared_ptr to itself

强颜欢笑 提交于 2019-12-22 06:57:00

问题


The following program crashes with a bad glibc double free error:

#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):

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. 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 ):

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.

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?

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[]. The idea is to use the std::shared_ptr::reset() to replace the deleter with a no-op deleter. The alternative is to wrap the code with a try { stuff() } catch( ... ) { delete x; throw;} kind of block.


回答1:


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):

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

Effects: Equivalent to 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. 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.

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. Perhaps you can change your design to use std::unique_ptr<T>? It's always possible to create a std::shared_ptr<T> out of it if you need to, eventually. (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[]>.)



来源:https://stackoverflow.com/questions/9785656/what-happens-if-i-reset-a-stdshared-ptr-to-itself

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!