[英]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[]
. 我目前正在试图弄清楚如何临时管理由
new
和new[]
创建的对象的裸指针。 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.