据我所知,分配的共享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;
}
那么交换背后的神奇之处是什么呢?
答案 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)之前,如果有自我指配(或等效)。
复制交换习语改为:
复制交换可以用作一般易于编写的赋值,但它不会重用lhs的内部资源,这会降低成本效率。在这种情况下,这并不重要,因为lhs内部资源是指向共享状态的指针。
答案 2 :(得分:0)
在赋值运算符作用域(结束}
)结束时,原始sptr对象的引用计数将减1,因为r
不再指向它。因此,它在功能上完全符合您上面描述的内容。