有人能解释为什么每个人都是按值传递std::unique_ptr而不是通过rvalue引用吗?
根据我的观察,这需要调用一个额外的move构造函数。
下面是一个类包含“指针”的例子。它需要3次移动调用(按值计算),而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{});
}发布于 2022-04-19 20:26:17
通过引用( rvalue或其他方式)传递一个unique_ptr并不会实际移动任何东西,所以您不能仅仅通过查看函数声明就知道是否会发生移动。
另一方面,传递一个unique_ptr值可以保证传入指针将被移出,所以甚至无需查看您所知道的调用该函数的文档就可以释放出指针的所有权。
发布于 2022-04-19 20:26:35
出于同样的原因,人们传递int而不是const int&。
std::unique_ptr只是一个RAII包装器,围绕一个指针值,所以移动它只是复制一个寄存器宽度值,然后对源进行归零。这是如此琐碎,没有真正的好处,避免采取行动。毕竟,传递引用的成本(如果不是内联的话)也是传递指针的成本,所以按引用传递可能效率较低(因为如果没有内联,它必须遵循对实际内存的引用,然后从那里提取值;堆栈的顶部可能在L1缓存中,谁知道它存储的位置在哪里?)
在实践中,这其中的大部分都将被启用优化,并且这两种方法都会得到相同的结果。当通过引用传递没有好处的时候,传递值是一个很好的默认,那么为什么不这样做呢?
发布于 2022-04-19 20:29:25
为什么每个人都按值传递std::unique_ptr而不是rvalue引用?
这可能更常见,但并不是“每个人”。
std::unique_ptr&&参数的缺点是它不显式地与调用方通信指针是否会被移出。它可能总是移动,也可能取决于某种条件。您必须了解实现,或者至少要知道API文档才能确定。std::unique_ptr参数的相应优点是它单独告诉读取器声明函数将获得指针的所有权。因此,使用std::unique_ptr参数可能是一个很好的选择,也可能是它更常见的原因之一。
std::unique_ptr&&的好处是避免额外的移动。然而,移动一个std::unique_ptr是一个非常快的操作。与内存分配本身相比,这是微不足道的。在大多数情况下,这并不重要。
两者之间的差别相当微妙。std::unique_ptr&&参数可能会在您测量移动成本很高的情况下考虑。这不是很普遍。或者,如果您的API可能在成本可能很高的情况下使用。如果您正在编写一个公共API,很难证明这种情况永远不会发生,所以这是一个更有可能使用的论点。
https://stackoverflow.com/questions/71930850
复制相似问题