boost shared_ptr: operator=和reset之间有什么区别?

14

以下两段代码有何不同?哪种更可取?

operator=

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...

1
http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/shared_ptr.htm#Members - DumbCoder
4个回答

17

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的评论? - Jon
使用new构建对象并用它初始化一个shared_ptr是一个两步过程。理论上,创建对象可能会成功,但初始化shared_ptr可能会失败,在这种情况下,您将泄漏内存,除非您明确处理该情况。 make_shared为您处理这个问题。根据文档,这也更快。 - Björn Pollex

3

operator= 接受另一个 shared_ptr 作为参数,从而创建另一个副本(并增加引用计数),而 reset() 接受一个指针和可选的删除器,因此实际上在当前 shared_ptr 上创建一个新的 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;
}

两个函数的作用类似,它们会释放控制已包含的内容(如果有的话),并管理不同的指针。

1
“reset” 还可以重载以接受另一个共享指针,此时它相当于赋值操作。 - Mike Seymour
CashCow:你能解释一下在你的 operator= 实现中,shared_ptr shared(other); 这行代码的作用吗? - freitass

2

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

赋值在逻辑上等同于复制和交换,并且可能是这样实现的。所以foo = shared_ptr(p);等同于foo.swap(shared_ptr(p))。如果编译器运行得非常糟糕,可能会有额外的复制。

因此,在您提供的示例中,我认为它们之间没有太大区别。可能还有其他情况需要考虑。但是reset使用了与模板构造函数相同的基于模板的捕获静态类型的方式,因此就获取正确的删除器而言,您已经得到了保障。

赋值的主要用途是当您想要复制先前存在的shared_ptr以共享对同一对象的所有权时。当然,从临时变量进行赋值也可以正常工作,如果查看不同的reset重载,则它们反映了不同的构造函数。因此,我认为您可以通过任一方式实现相同的功能。


0

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

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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接