这是一个基本的问题,但我没有找到之前关于它的帖子。以下问题的标题听起来可能与我的问题相同,但问题本身与标题不匹配:is it better to use shared_ptr.reset or operator =?
我对std::shared_ptr
的reset()
成员函数的用途感到困惑:除了赋值运算符之外,它还贡献了什么?
具体地说,给出了定义:
auto p = std::make_shared<int>(1);
P= std::make_shared(5);p.reset(new int(5));
P= nullptr;p.reset();
如果这两行在两种情况下都是等价的,那么reset()
的用途是什么?
编辑:让我重新表述这个问题,以更好地强调其要点。问题是:有没有这样一种情况,reset()
让我们实现了一些没有它就不容易实现的事情?
发布于 2015-07-16 03:24:29
使用reset()
时,传递给reset的参数不必是托管对象(也不能是);而使用=
时,右侧必须是托管对象。
所以这两行代码给出了相同的最终结果:
p = std::make_shared<int>(5); // assign to a newly created shared pointer
p.reset(new int(5)); // take control of a newly created pointer
但我们不能:
p = new int(5); // compiler error no suitable overload
p.reset(std::make_shared<int>(5).get()); // uh oh undefined behavior
如果没有reset()
,您将无法将共享指针重新分配给不同的原始指针,除非创建一个共享指针并将其分配。如果没有=
,你就不能让一个共享指针指向另一个共享指针。
发布于 2015-07-16 04:01:22
在某些情况下,reset
可以避免动态内存分配。考虑一下代码
std::shared_ptr<int> p{new int{}}; // 1
p.reset(new int{}); // 2
在第1行,发生了2次动态内存分配,一次用于int
对象,另一次用于shared_ptr
的控制块,用于跟踪对托管对象的强/弱引用的数量。
在第2行,有一个新的int
对象的动态内存分配。在reset
的主体内,shared_ptr
将确定没有其他对以前管理的int
的强引用,因此它必须delete
它。因为也没有任何弱引用,所以它也可以释放控制块,但在这种情况下,实现重用相同的控制块将是谨慎的,因为它无论如何都必须分配一个新的控制块。
如果您必须始终使用赋值,则上述行为是不可能的。
std::shared_ptr<int> p{new int{}}; // 1
p = std::shared_ptr<int>{new int{}}; // 2
在本例中,对第2行的shared_ptr
构造函数的第二次调用已经分配了一个控制块,因此p
将不得不释放它自己的现有控制块。
发布于 2015-07-16 03:27:32
我不会包含你的第一个子问题背后的原理,即通过make_shared
构造和从指针构造之间的差异,因为这种差异在几个不同的位置突出显示,包括this excellent question。
但是,我认为区分使用reset
和operator=
是有建设性的。前者放弃对shared_ptr
管理的资源的所有权,如果shared_ptr
恰好是唯一的所有者,则通过销毁它,或者通过减少引用计数。后者意味着与另一个shared_ptr
共享所有权(除非您正在移动构造)。
正如我在注释中提到的,重要的是传递给reset
的指针不属于另一个共享的或唯一的指针,因为它会在两个独立的管理器被破坏时产生未定义的行为-它们都会尝试delete
资源。
reset
的一个用例可以是共享资源的延迟初始化。你只希望shared_ptr
管理一些资源,比如内存,如果你真的需要它的话。执行完全分配,例如:
std::shared_ptr<resource> shared_resource(new resource(/*construct a resource*/));
如果它从来没有真正需要过,可能是浪费的。要使用延迟初始化来实现这一点,可以应用如下内容:
std::shared_ptr<resource> shared_resource;
void use_resource()
{
if(!shared_resource)
{
shared_resource.reset(new resource(...));
}
shared_resource->do_foo();
}
在这种情况下使用reset
比使用swap
或分配给临时shared_ptr
更简洁。
https://stackoverflow.com/questions/31438714
复制相似问题