方法冗余移动调用的移动语义
Move semantic for method redundant move call
说我有这个class
struct Test {
std::string a;
void setA(std::string&& input) {
a = input;
input = "";
}
}
在这里,我将 input
的内容移动到 a
中,然后将 input
置于安全的可破坏状态。这是移动语义的 classic 使用,我可以避免复制。
现在说我有这个class
struct Test {
std::string a;
void setA(std::string&& input) {
DoSomeWork(input);
}
void DoSomeWork(std::string&& other) { /* ... */}
}
这仍然正确吗?还是应该使用 DoSomeWork(std::move(input));
?我不知道在这种情况下是否需要移动。
注.
在案例 1 中,我收到一个右值引用作为输入,我使用 classic 方法。
void setA(std::string&& input) {
a = input; //input is an rvalue referece and I "transfer" its content into a
input = ""; //maybe useless but in some books (including c++ primer) I've seen that it's good practice to "reset" the moved-from object and leave it in a destructable state!
我明白了。我无法理解的是:
void setA(std::string&& input) {
//recall that DoSomeWork accepts a std::string&&
DoSomeWork(input);
}
这里如果我想将input
传递给函数并移动它我不知道是否需要std::move
。我已经有一个右值引用,所以移动过程是自动的吗?还是需要 std::move
调用?
Here I move the content of input into a and then I leave input on a safe destructable state. This is the classic use of the move semantic where I can avoid copies.
不,你不是;那是一个副本。除非您在命名的 &&
上明确使用 std::move
,否则它总是 一个副本。
此外,当您正确执行移动时,将前一个对象放入 "safe destructable state" 不是您的责任;这是移动 constructor/assignment 操作员的责任。
Is this still correct?
如果 "correct" 是指 "perform a move",则不是。同样,如果您想从命名变量移动,您 必须 在其上使用 std::move
。这包括将其传递给右值引用参数。
唯一的例外是 return <named_variable>;
语句,即便如此,"named_variable" 必须命名一个值,而不是引用(尽管 C++20 可能允许隐式移动右值引用变量从这种方式)。
在函数签名中
void setA(std::string&& input) { /* ... */ }
变量input
绑定到一个右值,但它本身是一个左值。当你想从它移动构造另一个对象时,你需要事先将它转换为右值:
void setA(std::string&& input) {
a = std::move(input);
}
请注意,现在没有必要将 input
设置为空字符串。你根本不应该再碰这个变量了。当您将 input
传递给其他函数时,同样的推理也是如此:
void setA(std::string&& input) {
/* Cast to rvalue necessary to preserve "rvalue-ness" of the argument: */
DoSomeWork(std::move(input));
}
Here I move the content of input
into a
没有。您正在将 input
的内容复制到 a
。
您可能会混淆类型和 value categories。作为命名参数,input
是一个左值;给定 a = input;
,将调用复制赋值运算符,但不会调用移动赋值运算符。
and then I leave input
on a safe destructable state.
多此一举,交给std::string
的移动赋值运算符吧。
是的,您应该使用 std::move
将 input
转换为右值,例如
void setA(std::string&& input) {
a = std::move(input); // input is move assigned to a, and left with undetermined but valid state
}
和
void setA(std::string&& input) {
DoSomeWork(std::move(input));
}
说我有这个class
struct Test {
std::string a;
void setA(std::string&& input) {
a = input;
input = "";
}
}
在这里,我将 input
的内容移动到 a
中,然后将 input
置于安全的可破坏状态。这是移动语义的 classic 使用,我可以避免复制。
现在说我有这个class
struct Test {
std::string a;
void setA(std::string&& input) {
DoSomeWork(input);
}
void DoSomeWork(std::string&& other) { /* ... */}
}
这仍然正确吗?还是应该使用 DoSomeWork(std::move(input));
?我不知道在这种情况下是否需要移动。
注. 在案例 1 中,我收到一个右值引用作为输入,我使用 classic 方法。
void setA(std::string&& input) {
a = input; //input is an rvalue referece and I "transfer" its content into a
input = ""; //maybe useless but in some books (including c++ primer) I've seen that it's good practice to "reset" the moved-from object and leave it in a destructable state!
我明白了。我无法理解的是:
void setA(std::string&& input) {
//recall that DoSomeWork accepts a std::string&&
DoSomeWork(input);
}
这里如果我想将input
传递给函数并移动它我不知道是否需要std::move
。我已经有一个右值引用,所以移动过程是自动的吗?还是需要 std::move
调用?
Here I move the content of input into a and then I leave input on a safe destructable state. This is the classic use of the move semantic where I can avoid copies.
不,你不是;那是一个副本。除非您在命名的 &&
上明确使用 std::move
,否则它总是 一个副本。
此外,当您正确执行移动时,将前一个对象放入 "safe destructable state" 不是您的责任;这是移动 constructor/assignment 操作员的责任。
Is this still correct?
如果 "correct" 是指 "perform a move",则不是。同样,如果您想从命名变量移动,您 必须 在其上使用 std::move
。这包括将其传递给右值引用参数。
唯一的例外是 return <named_variable>;
语句,即便如此,"named_variable" 必须命名一个值,而不是引用(尽管 C++20 可能允许隐式移动右值引用变量从这种方式)。
在函数签名中
void setA(std::string&& input) { /* ... */ }
变量input
绑定到一个右值,但它本身是一个左值。当你想从它移动构造另一个对象时,你需要事先将它转换为右值:
void setA(std::string&& input) {
a = std::move(input);
}
请注意,现在没有必要将 input
设置为空字符串。你根本不应该再碰这个变量了。当您将 input
传递给其他函数时,同样的推理也是如此:
void setA(std::string&& input) {
/* Cast to rvalue necessary to preserve "rvalue-ness" of the argument: */
DoSomeWork(std::move(input));
}
Here I move the content of
input
intoa
没有。您正在将 input
的内容复制到 a
。
您可能会混淆类型和 value categories。作为命名参数,input
是一个左值;给定 a = input;
,将调用复制赋值运算符,但不会调用移动赋值运算符。
and then I leave
input
on a safe destructable state.
多此一举,交给std::string
的移动赋值运算符吧。
是的,您应该使用 std::move
将 input
转换为右值,例如
void setA(std::string&& input) {
a = std::move(input); // input is move assigned to a, and left with undetermined but valid state
}
和
void setA(std::string&& input) {
DoSomeWork(std::move(input));
}