关于c ++:std ::进入static_pointer_cast:为什么static_pointer_cast没有右值引用重载?

std::move into static_pointer_cast: Why doesn't static_pointer_cast have an rvalue reference overload?

假设我们有一个功能,希望按值共享一个指针。 (在现实生活中的示例中,我通过右值引用来接受它,并将其转发给成员。)

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

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

1
2
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的重载来获取右值引用,因此该移动不会产生任何效果:

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

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


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

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

不会做任何多余的refcounter增量/减量。 首先,让我观察到这实际上根本不是赋值,而是ptr的构造。 显然,它是由一个临时对象构造的,并且显然,该临时对象是另一种类型。 将被匹配的构造函数的签名是(http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr):

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

在注释中说:

Move-constructs a shared_ptr from r. After the construction, *this contains a copy of the previous state of r, r is empty and its stored pointer is null. The template overload doesn't participate in overload resolution if Y* is not implicitly convertible to T*

在这种情况下,YDerivedTBase,因此很明显,我们得到了从Y*T*的隐式转换,因此构造函数是合法的。 严格来说,允许引用计数首先增加到2,然后再减少到1可能符合要求。但是显然,这违反了move构造函数的全部目的,因此我非常怀疑这是如何实现的。