C++ 冗余移动调用的移动语义方法

C++ 冗余移动调用的移动语义方法,c++,c++11,move-semantics,C++,C++11,Move Semantics,说我有这个班 struct Test { std::string a; void setA(std::string&& input) { a = input; input = ""; } } struct Test { std::string a; void setA(std::string&& input) { DoSomeWork(input); } void DoSomeWork(std::string&

说我有这个班

struct Test {
  std::string a;
  void setA(std::string&& input) {
    a = input;
    input = "";
  }
}
struct Test {
  std::string a;
  void setA(std::string&& input) {
    DoSomeWork(input);
  }
  void DoSomeWork(std::string&& other) { /* ... */}
}
在这里,我将
input
的内容移动到
a
中,然后将
input
置于安全的可销毁状态。这是移动语义的经典用法,可以避免复制

现在说我有这门课

struct Test {
  std::string a;
  void setA(std::string&& input) {
    a = input;
    input = "";
  }
}
struct Test {
  std::string a;
  void setA(std::string&& input) {
    DoSomeWork(input);
  }
  void DoSomeWork(std::string&& other) { /* ... */}
}
这仍然正确吗?或者我应该使用
DoSomeWork(std::move(input))?我不知道在这种情况下是否需要搬家


注意。 在案例1中,我收到一个右值引用作为输入,并使用经典方法

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

在这里,我将输入的内容移动到一个安全的可破坏状态,然后将输入保持在一个安全的可破坏状态。这是移动语义的经典用法,可以避免复制

不,你不是;那是一份副本。除非在命名的
&&
上明确使用
std::move
,否则它始终是一个副本

另外,当你正确地执行一个移动时,将前一个对象置于“安全可破坏状态”不是你的责任;这是移动构造函数/赋值操作符的责任

这仍然正确吗

如果“correct”的意思是“执行移动”,则不是。同样,如果要从命名变量移动,必须在其上使用
std::move
。这包括将其传递给右值引用参数

唯一的例外是
返回语句,即使这样,“named_variable”也必须命名一个值,而不是一个引用(尽管C++20可能允许以这种方式隐式移动右值引用变量)

在这里,我将输入的内容移动到一个安全的可破坏状态,然后将输入保持在一个安全的可破坏状态。这是移动语义的经典用法,可以避免复制

不,你不是;那是一份副本。除非在命名的
&&
上明确使用
std::move
,否则它始终是一个副本

另外,当你正确地执行一个移动时,将前一个对象置于“安全可破坏状态”不是你的责任;这是移动构造函数/赋值操作符的责任

这仍然正确吗

如果“correct”的意思是“执行移动”,则不是。同样,如果要从命名变量移动,必须在其上使用
std::move
。这包括将其传递给右值引用参数


唯一的例外是
返回语句,即使这样,“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));
}

在函数签名中

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));
}
这里我将
input
的内容移动到
a

否。您正在将
input
的内容复制到
a

您可能会混淆类型和类型。作为命名参数,
input
是左值;给定
a=输入,将调用复制分配运算符,但不调用移动分配运算符

然后我将
input
置于安全的可破坏状态

这是多余的,工作应该留给
std::string
的移动赋值操作符完成

是,您应该使用将
输入转换为右值,例如

void setA(std::string&& input) {
  a = std::move(input); // input is move assigned to a, and left with undetermined but valid state
}

这里我将
input
的内容移动到
a

否。您正在将
input
的内容复制到
a

您可能会混淆类型和类型。作为命名参数,
input
是左值;给定
a=输入,将调用复制分配运算符,但不调用移动分配运算符

然后我将
input
置于安全的可破坏状态

这是多余的,工作应该留给
std::string
的移动赋值操作符完成

是,您应该使用将
输入转换为右值,例如

void setA(std::string&& input) {
  a = std::move(input); // input is move assigned to a, and left with undetermined but valid state
}


哪本C++入门书说手动把物体移动到一个有效的状态?移动构造函数应该自动为您做这件事。C++的底漆手册是如何将对象移动到有效状态的?移动构造函数应该自动为您执行此操作。我误解了&&then的用法!我认为拥有
std::string&&input
ad,那么赋值
a=input
就足够移动了。但是现在我明白了有效的移动只能由
std::move
执行,我误解了&&then!我认为拥有
std::string&&input
ad,那么赋值
a=input
就足够移动了。但是现在我知道有效的移动只能由
std::move
执行,谢谢。是的,我误解了这个概念!我认为将输入声明为&&就足以启用移动。但是根据你所写的,每次我想做一个move@RosannaTrevisan雷米