如果我重置一个std :: shared_ptr本身会发生什么 [英] What happens if I reset a std::shared_ptr to itself

查看:422
本文介绍了如果我重置一个std :: shared_ptr本身会发生什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下程序崩溃时出现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<< 复位前<< std :: endl;
f.reset(f.get());
std :: cout<< 复位后<< std :: endl;
return 0;
}



从这里我得到以下输出(后跟glibc错误):

  foo created 
重置前
foo destructed
重置后
foo destructed

很明显,在这种情况下,对象被销毁两次。一次通过复位,一次通过 std :: shared_ptr 超出范围。这实际上是我的期望。



cppreference 但是,我发现以下文本(位于 http://en.cppreference。 com / w / cpp / memory / shared_ptr / reset ):


如果*已经拥有一个对象,最后一个shared_ptr拥有它,对象被破坏通过拥有的删除,除非ptr是一个指针。


说,对象不应该像在我的例子中被销毁。非常令人惊讶,但如果标准说的这样。我不知何故误读了这个,或者是 std :: shared_ptr 的实现我可以不符合标准吗?



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



我目前正试图找出如何临时管理裸指针到由 new new [] 。这个想法是使用 std :: shared_ptr :: reset()用无操作删除器替换删除器。另一种方法是用 try {stuff()} catch(...){delete x;

解决方案 c > reset 在20.7.2.2.4中给出了shared_ptr修饰符[util.smartptr.shared.mod],第3段(来自n3290):

 模板< class Y> void reset(Y * p); 

效果:等效于 shared_ptr(p).swap / code>。


正如你所看到的那样, shared_ptr(p) construction会为 p 创建一个带有新删除器的新计数,所以没有什么可以脱离它。它真的是最好的认为 std :: shared_ptr< T> :: get 作为严格观察员,并使用它来处理生命周期管理是一个告诉迹象,有



另一方面, std :: unique_ptr< T> release ,这正是你需要的时候,你需要立即处理和处理所有权。也许你可以改变你的设计使用 std :: unique_ptr< T> ?如果你需要,总是可以创建一个 std :: shared_ptr< T> 。 (尽管 std :: shared_ptr< T> std :: unique_ptr< T> 中选择删除者,您仍然需要在数组情况下的特殊处理,因为您可能希望 std :: shared_ptr< T *> std :: unique_ptr< T [ > 。)


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.

解决方案

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[]>.)

这篇关于如果我重置一个std :: shared_ptr本身会发生什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆