【问题标题】:boost shared_ptr: difference between operator= and reset?boost shared_ptr:operator=和reset之间的区别?
【发布时间】:2011-03-18 12:14:32
【问题描述】:

下面的两段代码有什么不同吗?他们中的任何一个都比另一个更可取吗?

操作员=

boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo = boost::shared_ptr<Blah>(new Blah()); // Involves creation and copy of a shared_ptr?

重置

boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo.reset(new Blah()); // foo.ptr should point now to a new Blah object

注意:我需要定义 shared_ptr 然后将其设置在不同的行中,因为我在一段代码中使用它:

boost::shared_ptr<Blah> foo;
try
{
  foo.reset...
}
foo...

【问题讨论】:

标签: c++ boost shared-ptr


【解决方案1】:

operator=shared_ptr 分配给shared_ptr,而reset 使shared_ptr 获得指针的所有权。因此,基本上您发布的示例之间没有区别。也就是说,你不应该喜欢它们,而只使用make_shared

foo = boost::make_shared<Blah>();

此外,如果可能的话,您可以通过将 try-catch 块包装在一个单独的函数中来避免在没有初始化的情况下声明 shared_ptr,该函数只是将 shared_ptr 返回到新创建的对象:

boost::shared_ptr<Blah> createBlah() {
    try {
        // do stuff
        return newBlah;
    }
    catch ...
}

【讨论】:

  • 您能否证明您的评论认为 make_shared 应该是首选?
  • 使用new 建立对象并用它初始化shared_ptr 是一个两步过程。理论上,创建对象可能会成功,但初始化 shared_ptr 可能会失败,在这种情况下您会泄漏内存,除非您明确处理这种情况。 make_shared 会为您解决这些问题。根据documentation,速度也更快。
【解决方案2】:

operator= 将另一个 shared_ptr 作为参数,从而创建另一个副本(并增加引用计数),而 reset() 采用一个指针和可选的删除器,因此实际上在当前副本之上创建了一个新的 shared_ptr .

reset 等价于(并且可能实现为)

void reset(T p, D d)
{
   shared_ptr shared(p,d);
   swap( shared );
}

operator= 很可能实现为:

shared_ptr& operator=( shared_ptr const& other )
{
   shared_ptr shared(other);
   swap(other);
   return *this;
}

这两个函数的相似之处在于它们释放了对它们已经包含的内容(如果有的话)的控制,并改为管理不同的指针。

【讨论】:

  • reset 也被重载以获取另一个共享指针,在这种情况下它相当于赋值。
  • CashCow:您能解释一下shared_ptr shared(other); 行在您的operator= 实现中的作用吗?
【解决方案3】:

foo.reset(p) 被定义为等同于shared_ptr(p).swap(foo)

分配在逻辑上等同于复制和交换,并且可能以这种方式实现。所以foo = shared_ptr(p); 等价于foo.swap(shared_ptr(p))。如果编译器遇到非常糟糕的一天,可能会在其中添加一个额外的副本。

因此,在您提供的示例中,我认为它们之间没有太多选择。可能还有其他重要的情况。但是 reset 对 p 的静态类型进行与模板构造函数相同的基于模板的捕获,因此就获取正确的删除器而言,您已经涵盖了。

赋值的主要用途是当您想要复制先前存在的shared_ptr 以共享同一对象的所有权时。当然,从临时分配时它也可以正常工作,如果您查看不同的reset 重载,它们会反映不同的构造函数。所以我怀疑你可以通过任何一种方式实现相同的目标。

【讨论】:

    【解决方案4】:

    赋值运算符从现有的共享对象创建一个新的共享对象,增加引用计数

    CSharedObj& CSharedObj::operator=(CSharedObj& r) noexcept
    { 
         if(*this != r){
            //detach from the previous ownership
            if(0 == dec()) delete m_pControlObj;
            //attach to the new control object and increment the reference count
            r.inc();
            m_pControlObj = r.m_pControlObj;
        }
        return *this;
    }
    

    虽然重置调用不会创建新的共享对象,而是创建新的所有权 - 附加到新的底层指针(通过控制对象)

    void CSharedObj::reset(Ptr pointee) noexcept
    {
       //check if this is a last reference-detach from the previous ownership
       if(0==dec()) delete m_pControlObj;
       // create the ownership over the new pointee (refCnt = 1)
       m_pControlObj = new (std::nothrow) CControlObj(pointee);
    }
    

    【讨论】:

      猜你喜欢
      • 2018-10-07
      • 2019-03-11
      • 1970-01-01
      • 2023-03-23
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      • 2018-08-23
      • 2016-05-12
      相关资源
      最近更新 更多