首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >std::shared_ptr: reset()与赋值

std::shared_ptr: reset()与赋值
EN

Stack Overflow用户
提问于 2015-07-16 02:52:18
回答 4查看 30.3K关注 0票数 55

这是一个基本的问题,但我没有找到之前关于它的帖子。以下问题的标题听起来可能与我的问题相同,但问题本身与标题不匹配:is it better to use shared_ptr.reset or operator =?

我对std::shared_ptrreset()成员函数的用途感到困惑:除了赋值运算符之外,它还贡献了什么?

具体地说,给出了定义:

代码语言:javascript
复制
auto p = std::make_shared<int>(1);

  1. 是以下两行的等价物:

P= std::make_shared(5);p.reset(new int(5));

P= nullptr;p.reset();

如果这两行在两种情况下都是等价的,那么reset()的用途是什么?

编辑:让我重新表述这个问题,以更好地强调其要点。问题是:有没有这样一种情况,reset()让我们实现了一些没有它就不容易实现的事情?

EN

回答 4

Stack Overflow用户

发布于 2015-07-16 03:24:29

使用reset()时,传递给reset的参数不必是托管对象(也不能是);而使用=时,右侧必须是托管对象。

所以这两行代码给出了相同的最终结果:

代码语言:javascript
复制
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

但我们不能:

代码语言:javascript
复制
p = new int(5); // compiler error no suitable overload
p.reset(std::make_shared<int>(5).get()); // uh oh undefined behavior

如果没有reset(),您将无法将共享指针重新分配给不同的原始指针,除非创建一个共享指针并将其分配。如果没有=,你就不能让一个共享指针指向另一个共享指针。

票数 35
EN

Stack Overflow用户

发布于 2015-07-16 04:01:22

在某些情况下,reset可以避免动态内存分配。考虑一下代码

代码语言:javascript
复制
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它。因为也没有任何弱引用,所以它也可以释放控制块,但在这种情况下,实现重用相同的控制块将是谨慎的,因为它无论如何都必须分配一个新的控制块。

如果您必须始终使用赋值,则上述行为是不可能的。

代码语言:javascript
复制
std::shared_ptr<int> p{new int{}};    // 1
p = std::shared_ptr<int>{new int{}};  // 2

在本例中,对第2行的shared_ptr构造函数的第二次调用已经分配了一个控制块,因此p将不得不释放它自己的现有控制块。

票数 6
EN

Stack Overflow用户

发布于 2015-07-16 03:27:32

我不会包含你的第一个子问题背后的原理,即通过make_shared构造和从指针构造之间的差异,因为这种差异在几个不同的位置突出显示,包括this excellent question

但是,我认为区分使用resetoperator=是有建设性的。前者放弃对shared_ptr管理的资源的所有权,如果shared_ptr恰好是唯一的所有者,则通过销毁它,或者通过减少引用计数。后者意味着与另一个shared_ptr共享所有权(除非您正在移动构造)。

正如我在注释中提到的,重要的是传递给reset的指针不属于另一个共享的或唯一的指针,因为它会在两个独立的管理器被破坏时产生未定义的行为-它们都会尝试delete资源。

reset的一个用例可以是共享资源的延迟初始化。你只希望shared_ptr管理一些资源,比如内存,如果你真的需要它的话。执行完全分配,例如:

代码语言:javascript
复制
std::shared_ptr<resource> shared_resource(new resource(/*construct a resource*/));

如果它从来没有真正需要过,可能是浪费的。要使用延迟初始化来实现这一点,可以应用如下内容:

代码语言:javascript
复制
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更简洁。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31438714

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档