std :: move into static_pointer_cast:为什么static_pointer_cast没有rvalue引用重载?

时间:2017-05-03 22:39:53

标签: c++ c++11

假设我们有一个函数,期望按值分享指针。 (在现实生活中的例子中,我通过右值参考将其转发给成员。)

void f(std::shared_ptr<Derived> ptr) { ... }

但是我们只有一个指向基类的共享指针,因此我们使用static_pointer_cast

std::shared_ptr<Base> ptr = std::make_shared<Derived>();
f(std::static_pointer_cast<Derived>(ptr));

第一个赋值(从临时构造ptr)是触发引用计数的原子递增和递减还是共享指针移动? (请注意,它正在升级。)

static_pointer_cast内,引用计数的原子增量。如果我们不再需要ptr,我们会将其移至f。但由于static_pointer_cast没有超载参与右值参考,此举不会产生任何影响:

f(std::static_pointer_cast<Derived>(std::move(ptr)));

一旦ptr被破坏,我们仍然有原子增量和相应的原子减量。为什么没有这样的过载?

1 个答案:

答案 0 :(得分:3)

我可以回答你问题的第一部分,但不是第二部分。虽然我不确定它是否符合标准,但我很确定:

std::shared_ptr<Base> ptr = std::make_shared<Derived>();

不会做任何无关的refcounter增量/减量。首先,让我观察一下,这实际上不是一项任务,而是ptr的构建。显然,它是由一个临时构建的,显然临时属于不同类型。将匹配的构造函数的签名是(http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr):

template< class Y > 
shared_ptr( shared_ptr<Y>&& r );

在说明中说:

  

从r构造一个shared_ptr。在构造之后,*它包含r的先前状态的副本,r为空并且其存储的指针为空。如果Y *不可隐式转换为T *

,则模板重载不参与重载解析

在这种情况下,YDerivedTBase,因此很明显我们会从Y*隐式转换为T*,所以构造函数是合法的。严格来说,它可能符合允许引用计数首先上升到2,然后降回到1.但显然这会破坏移动构造函数的整个目的,所以我强烈怀疑这是如何实现的。