ES.56:只在需要将一个对象显式移动到另外的作用域时使用std::move
We move, rather than copy, to avoid duplication and for improved performance.
我们使用move而不是copy是为了避免不必要的重复并提高性能。
A move typically leaves behind an empty object (C.64), which can be surprising or even dangerous, so we try to avoid moving from lvalues (they might be accessed later).
移动操作一般会留下一个空对象(C.64),它可能引起误解甚至危险。因此我们努力避免移动左值(它们可能在后续代码中被使用)。
Notes(注意)
Moving is done implicitly when the source is an rvalue (e.g., value in a return treatment or a function result), so don't pointlessly complicate code in those cases by writing move explicitly. Instead, write short functions that return values, and both the function's return and the caller's accepting of the return will be optimized naturally.
如果源数据是右值,移动操作会隐式进行(例如return处理或函数的返回值),在这种情况下进行显式移动操作,会导致代码被漫无目标地的复杂化。相反,编写带返回值的简短函数,这样无论是函数的返回值还是调用侧的接受动作都可以很自然地被优化。
In general, following the guidelines in this document (including not making variables' scopes needlessly large, writing short functions that return values, returning local variables) help eliminate most need for explicit std::move.
通常情况下,遵循本文档中的准则(包括不要不必要地扩大变量作用域,编写带返回值的简短函数,返回局部变量等)可以帮助消除显式执行std::move的大部分需求。
Explicit move is needed to explicitly move an object to another scope, notably to pass it to a "sink" function and in the implementations of the move operations themselves (move constructor, move assignment operator) and swap operations.
在显式移动一个对象到另外的作用域时,显式移动是有必要的。特别是:
1.将对象传递给一个“下沉”函数时(接管变量所有权的函数,译者注)
2.实现对象自身移动操作(移动构造函数,移动赋值运算符)和交换操作时
Example, bad(反面示例)
void sink(X&& x); // sink takes ownership of x
void user()
{
X x;
// error: cannot bind an lvalue to a rvalue reference
sink(x);
// OK: sink takes the contents of x, x must now be assumed to be empty
sink(std::move(x));
// ...
// probably a mistake
use(x);
}
Usually, a std::move() is used as an argument to a && parameter. And after you do that, assume the object has been moved from (see C.64) and don't read its state again until you first set it to a new value.
通常情况下,std::move()作为为&&参数提供实参。而且在移动之后,应该认为对象已经被移走(参见C.64)并且在赋予新值之前不要获取对象的状态。
void f() {
string s1 = "supercalifragilisticexpialidocious";
string s2 = s1; // ok, takes a copy
assert(s1 == "supercalifragilisticexpialidocious"); // ok
// bad, if you want to keep using s1's value
string s3 = move(s1);
// bad, assert will likely fail, s1 likely changed
assert(s1 == "supercalifragilisticexpialidocious");
}
void sink(unique_ptr<widget> p); // pass ownership of p to sink()
void f() {
auto w = make_unique<widget>();
// ...
sink(std::move(w)); // ok, give to sink()
// ...
sink(w); // Error: unique_ptr is carefully designed so that you cannot copy it
}
std::move() is a cast to && in disguise; it doesn't itself move anything, but marks a named object as a candidate that can be moved from. The language already knows the common cases where objects can be moved from, especially when returning values from functions, so don't complicate code with redundant std::move()'s.
std::move()实际上是目标为&&的类型转换;它自己不会移动任何东西,而是将命名对象标记为一个移出操作的候选者。语言已经知道对象可以被移出的一般情况,特别是函数的返回值,因此不要因为多余的std::move导致代码复杂化。
Never write std::move() just because you've heard "it's more efficient." In general, don't believe claims of "efficiency" without data (???). In general, don't complicate your code without reason (??). Never write std::move() on a const object, it is silently transformed into a copy (see Item 23 in Meyers15)
永远不要只是因为听说它更高效就使用std::move。通常不要相信那些脱离具体数据的所谓“高效”。通常不要没有理由地让代码复杂化。永远不要对常量对象调用std::move(),这会不知不觉地产生一个拷贝。
Example, bad(反面示例)
vector<int> make_vector() {
vector<int> result;
// ... load result with data
return std::move(result); // bad; just write "return result;"
}
Never write return move(local_variable);, because the language already knows the variable is a move candidate. Writing move in this code won't help, and can actually be detrimental because on some compilers it interferes with RVO (the return value optimization) by creating an additional reference alias to the local variable.
永远不要返回局部变量的移动结果;因为语言已经知道这个变量可以作为移动操作的候选,在这种代码中增加move代码不但没有任何帮助,而且对于某些编译器,由于产生了额外的指向局部变量的引用,增加move代码会影响RVO(返回值优化)的正常执行。
Example, bad(反面示例)
vector<int> v = std::move(make_vector()); // bad; the std::move is entirely redundant
Never write move on a returned value such as x = move(f()); where f returns by value. The language already knows that a returned value is a temporary object that can be moved from.
如果函数f以传值方式返回结果,永远不要对这个返回值调用move操作,例如X=move(f());语言已经知道返回值是临时变量并且可以进行移出操作。
Example(示例)
void mover(X&& x) {
call_something(std::move(x)); // ok
call_something(std::forward<X>(x)); // bad, don't std::forward an rvalue reference
call_something(x); // suspicious, why not std::move?
}
template<class T>
void forwarder(T&& t) {
call_something(std::move(t)); // bad, don't std::move a forwarding reference
call_something(std::forward<T>(t)); // ok
call_something(t); // suspicious, why not std::forward?
}
原文链接
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es56-write-stdmove-only-when-you-need-to-explicitly-move-an-object-to-another-scope