2015-12-14 90 views
2

我扫描shared_ptr实施GCC 5,我看到以下内容:GCC shared_ptr的拷贝赋值实施

__shared_ptr& 
    operator=(__shared_ptr&& __r) noexcept 
    { 
    __shared_ptr(std::move(__r)).swap(*this); 
    return *this; 
    } 

我的问题是,为什么交换前的临时的额外举措构建?我认为编译将消除任何额外的开销 - 但为什么不只是拨打__r.swap(*this)?我错过了一些聪明的副作用吗?

我看到类中的其他函数也使用相同的模式实现,我可以理解接受const引用但接受右值引用的情况吗?

回答

7

首先,这就是标准所说的,海湾合作委员会只是遵循这封信。

这样,赋值运算符有一个后置条件,即__r.empty(),这将不会通过您的建议来实现,因此,如您所建议的那样实施它将对标准说明有不同的影响,因此将不符合要求。

即这一说法成立:

auto p1 = std::make_shared<int>(1); 
auto p2 = std::make_shared<int>(2); 
p1 = std::move(p2); 
assert(!p2); 

的“聪明的副作用”是,你创建一个新的 shared_ptr的,这最终交换后举行的*this旧值,然后熄灭的范围。这意味着*this的旧值不会以__r结束。

+0

这是有道理的,这些天我应该停止拖延和扫描标准... – Nim

1

因为我们需要调用一个引用右值的析构函数来减少实例数量。

1

通过将__r的内容移动到一个临时文件中,并将其作为函数return s销毁,它确保移开的对象__r所指的内容处于空状态。我想他们想把这个逻辑放在一个地方,移动构造函数,看起来像这样。

__shared_ptr(__shared_ptr&& __r) noexcept 
    : _M_ptr(__r._M_ptr), _M_refcount() 
{ 
    _M_refcount._M_swap(__r._M_refcount); 
    __r._M_ptr = 0; 
} 

就我个人而言,我更喜欢下面的实现,据我所知,它是等价的。

widget& 
operator=(widget&& other) noexcept 
{ 
    widget temp {}; 
    swap(*this, temp); 
    swap(*this, other); 
    return *this; 
} 

它可以补充一个像这样实现的移动构造函数。

widget(widget&& other) noexcept : widget {} 
{ 
    swap(*this, other); 
} 

我假设有一个

void 
swap(widget&, widget&) noexcept; 

重载ADL可以找到和的widget默认构造函数是noexcept

+0

Erm,你的实现说你必须默认构建一个'Widget'作为做任务的一部分,并说你有移动/复制一个小部件的内容两次? –

+0

@AndreKostur没错,只是它总是一个动作,从来没有一个副本。 – 5gon12eder

+0

我同意,小部件本身会移动两次,但是不支持移动的小部件的任何成员都会被复制两次。 –