为什么共享指针赋值'交换'?

时间:2015-03-31 09:56:02

标签: c++ boost shared-ptr swap

据我所知,分配的共享ptr应该表现得像:

a)if (--this->count == 0) { release this->count and this->obj }

b)this->count = r->count, this->obj = r->obj;

提升的作用仅仅是

shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT
{
    this_type(r).swap(*this);
    return *this;
}

那么交换背后的神奇之处是什么呢?

3 个答案:

答案 0 :(得分:7)

  

a)if(--this-> count == 0){release this-> count and this-> obj}

不,shared_ptr保留两个计数,一个用于对象,一个用于包含引用计数的控制块。当第一个达到零时释放this->obj,当第二个达到零时释放this->count(和第二个计数)。

  

b)this-> count = r-> count,this-> obj = r-> obj;

不,你错过了引用计数增量。另外,正如Yakk的回答所指出的那样,你必须先检查自我分配或增加右侧,以避免在自我分配时错误地破坏对象。

所以你的理解是不完整/不正确的,但是如果你遵循Boost代码,你会发现它完全正确。它会增加r对象的引用计数,交换所有必需的值,然后减少原始值*this的引用计数。

增加引用计数的步骤已经在复制构造函数中实现,因此它会重用它。

交换所有必要值的步骤已在swap成员中实现,因此它使用了该步骤。

减少引用计数(并在需要时释放任何内容)的步骤已经由析构函数完成,因此它使用它。

这是优秀的代码重用。另一种方法是重复所有与复制构造函数,交换成员和析构函数相同的代码,这将是多余的,容易出错。

答案 1 :(得分:2)

这是复制交换习语。它并不总是有效的,但在这种情况下它是。

要分配引用计数对象,首先(a)增加右侧的引用计数,然后(b)减少左侧的引用计数,(c)将rhs的状态存储在LHS。

(b)和(c)的顺序仅在例外情况发生时才有意义,但(a)必须发生在(b)之前,如果有自我指配(或等效)。

复制交换习语改为:

  • (1)将rhs复制到临时。
  • (2)交换lhs状态与临时(包含rhs状态的副本)
  • (3)摧毁临时 这确实是(a)中的(a),然后是(c)中的(c),然后是(b)中的(3)。并且它以特别安全的方式执行:代码处于“奇怪”状态的唯一时间是在交换中,并且交换很容易进行异常证明。

复制交换可以用作一般易于编写的赋值,但它不会重用lhs的内部资源,这会降低成本效率。在这种情况下,这并不重要,因为lhs内部资源是指向共享状态的指针。

答案 2 :(得分:0)

在赋值运算符作用域(结束})结束时,原始sptr对象的引用计数将减1,因为r不再指向它。因此,它在功能上完全符合您上面描述的内容。