说我有这堂课
struct Test {
std::string a;
void setA(std::string&& input) {
a = input;
input = "";
}
}
在这里,我将input
的内容移至a
,然后将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
通话?
答案 0 :(得分:3)
在这里,我将
**" X mm rain expected in Y hours at your location"**
的内容移到for (var i = 0; i < myInputs.length; i++) { myInputs[i].addEventListener('blur', function (evt) { if(this.value!=this.defaultValue){ //value was changed now do your thing } }); myInputs[i].addEventListener('focus', function (evt) { evt.target.setAttribute("value",evt.target.value); }); }
不。您正在将input
的内容复制到a
。
您可能会混淆类型和value categories。作为命名参数,input
是一个左值;给定a
,将调用复制分配运算符,而不是移动分配运算符。
然后我将
input
置于安全的可破坏状态。
这是多余的,应将工作留给a = input;
的移动分配运算符。
是的,您应该使用std::move
将input
转换为右值,例如
std::string
和
input
答案 1 :(得分:2)
在功能签名中
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));
}
答案 2 :(得分:1)
在这里,我将输入内容移至a,然后将输入置于安全的可破坏状态。这是移动语义的经典用法,可以避免复制。
不,你不是。这是副本。除非您在命名的std::move
上明确使用&&
,否则它总是 副本。
此外,当您正确执行移动时,也不要将先前的对象置于“安全可破坏状态”。这是移动构造函数/赋值运算符的职责。
这仍然正确吗?
如果“正确”是指“执行动作”,否。同样,如果要从命名变量中移出,则必须 在其上使用std::move
。这包括将其传递给右值参考参数。
唯一的例外是return <named_variable>;
语句,即使这样,“ named_variable”也必须命名一个值,而不是引用(尽管C ++ 20可能允许以这种方式隐式移走右值引用变量)。