这个帖子的接受答案通过价值与通过右值参考传递说明:
对于仅移动类型(as
std::unique_ptr
),pass-by-value似乎是常态......
我对此有点怀疑.让我们说有一些不可复制的类型,Foo
移动也不便宜; 和一些Bar
有成员的类型Foo
.
class Foo {
public:
Foo(const Foo&) = delete;
Foo(Foo&&) { /* quite some work */ }
...
};
class Bar {
public:
Bar(Foo f) : f_(std::move(f)) {} // (1)
Bar(Foo&& f) : f_(std::move(f)) {} // (2)
// Assuming only one of (1) and (2) exists at a time
private:
Foo f_;
};
Run Code Online (Sandbox Code Playgroud)
然后为以下代码:
Foo f;
...
Bar bar(std::move(f));
Run Code Online (Sandbox Code Playgroud)
构造函数(1)引发2个移动构造,而构造函数(2)只引发1.我还记得在Scott Meyers的Effective Modern C++中读到这个但是不能立即记住哪个项目.
所以我的问题是,对于仅移动类型(或者更一般地说,当我们想要转移参数的所有权时),我们是否应该更倾向于通过rvalue-reference来获得更好的性能?
更新:我知道pass-by-value构造函数/赋值运算符(有时称为统一 ctors /赋值运算符)可以帮助消除重复的代码.我应该说我对以下情况更感兴趣:(1)性能很重要,(2)类型是不可复制的,因此没有重复的ctors /赋值运算符接受const
左值引用参数.
更新2:所以我找到了Scott Meyers关于具体问题的博客:http://scottmeyers.blogspot.com/2014/07/should-move-only-types-ever-be-passed.html.这篇博客讨论了他在有效现代C++第41项中提倡的原因:
考虑仅为可复制参数传递值... 移动便宜 ...... [和] 总是被复制.
在该项目中有关于按值传递与右值参考的广泛讨论,这里引用太多.关键是,两种方式都有各自的优点和缺点,但是为了转移仅移动对象的所有权,通过右值引用似乎更可取.
很难想象一个类的移动成本会很高:移动语义正是来自于在语义允许的情况下为副本提供快速替代方案的需要。
std::string
您带来了SSO的示例。然而,这个例子显然是有缺陷的(我怀疑他们甚至打开了优化),因为复制 16 个字节memcpy
应该需要大量的 CPU 周期,因为它可以用 1 个 SIMD 指令来实现来一次存储它们。另外,MSVC 10 确实很旧。
所以我的问题是,对于仅移动类型(或者更一般地说,当我们想要转移参数的所有权时),我们不应该更喜欢通过右值引用来获得更好的性能吗?
我不会谈论性能,因为它是一个非常特殊的方面,不能“一般地”进行分析。我们需要具体案例。此外,还需要考虑编译器优化;事实上,相当重。不要忘记彻底的性能分析。
std::unique_ptr
有点不同,因为(i)只能由于拥有语义而移动(ii)移动成本低廉。
我的看法。 我想说,如果您必须提供“更快”的替代方案作为 API,请同时提供两者 - 就像std::vector::push_back
. 正如你所说,它可能会有轻微的改进。
否则,即使对于仅移动类型,通过常量引用传递仍然有效,如果您认为不行,请选择按值传递。