为什么不通过右值引用接受 std::unique_ptr ?

ban*_*a36 6 c++

有人可以解释为什么每个人都std::unique_ptr按值传递而不是按右值引用传递吗?

据我观察,这需要调用额外的移动构造函数。

这是一个持有“指针”的类的示例。需要 3 个 move-ctor 调用才能按值获取它,而需要 2 个调用才能按引用获取它:

#include <memory>
#include <iostream>

class pointer {
public:
    pointer()
    { std::cerr << "ctor" << std::endl; }
    
    pointer(const pointer&)
    { std::cerr << "copy-ctor" << std::endl; }
    
    pointer& operator=(const pointer&)
    { std::cerr << "copy-assignment" << std::endl; return *this; }
    
    pointer(pointer&&)
    { std::cerr << "move-ctor" << std::endl; }
    
    pointer& operator=(pointer&&)
    { std::cerr << "move-assignment" << std::endl; return *this; }
    
    ~pointer()
    { std::cerr << "dtor" << std::endl; }
};

class A {
public:
    // V1
    A(pointer _ptr) : ptr(std::move(_ptr)) {}
        
    // V2
    A(pointer&& _ptr) : ptr(std::move(_ptr)) {}

private:
    pointer ptr;
};

int main() {
    // Three calls to move-ctor versus two calls if pass by rvalue reference
    auto ptr = pointer();
    A a(std::move(ptr));

    // Two calls to move-ctor always
    A a(pointer{});
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ica 15

通过引用、右值或其他方式传递unique_ptr,实际上不会移动任何东西,因此您无法仅通过查看函数声明来知道是否会发生移动。

另一方面,按值传递unique_ptr可以保证传入的指针将被移走,因此甚至不必查看文档,您就知道调用该函数可以将您从指针的所有权中释放出来。


Sha*_*ger 6

出于同样的原因,人们通过int而不是通过const int&

std::unique_ptr只是单个指针值的 RAII 包装器,因此移动它只是复制单个寄存器宽度值,然后将源清零。这实在是微不足道,避免这一举动并没有真正的好处。毕竟,传递引用(未内联时)的成本也是传递指针的成本,因此通过引用传递的效率可能较低(因为如果不内联,它必须遵循对真实内存的引用,然后拉取从那里取出值;堆栈顶部可能在L1缓存中,谁知道它存储的位置是不是?)。

在实践中,其中大部分都将与启用的优化相结合,并且两种方法都会得到相同的结果。当按引用传递没有任何好处时,按值传递是一个很好的默认值,那么为什么不这样做呢?