因此,这提供了预期的输出:
void f(std::string&& s)
{
s += " plus extra";
}
int main(void)
{
std::string str = "A string";
f( std::move(str) );
std::cout << str << std::endl;
return 0;
}
字符串加上额外的
也就是说,当我在Ideone上运行它时,它可以工作,但它是UB吗?在调用f
之前和之后添加额外的字符串初始化并没有改变任何东西。
答案 0 :(得分:18)
这是有效的,而不是UB。
它也是可怕的混淆代码。 std::move(s)
只不过是对右值的强制转换。它本身并不实际生成任何代码。它的唯一目的是将左值转换为右值,以便客户端代码可以重载lvalue / rvalue表达式(在这种情况下为string
)。
对于这种情况,你应该通过左值引用:
void f(std::string& s)
{
s += " plus extra";
}
...
f( str );
或者,传递值并返回一个新字符串:
std::string f(std::string s)
{
s += " plus extra";
return s;
}
...
str = f( std::move(str) );
答案 1 :(得分:10)
ruamel.yaml
无法移动任何内容。它表示某个对象可能是<#34; 从&#34;移动它的参数是 rvalue 。
您的代码有效且没有执行移动操作。
如果你从std::move
移动构造另一个字符串对象,那么在调用str
之后,你会得到f()
状态未指定的行为。 move-constructor执行实际的移动操作。
示例:
s
答案 2 :(得分:9)
代码有效,因为没有执行实际移动。以下是如何使其无效:
string f(std::string&& s) {
std::string res(std::move(s));
res += " plus extra";
return res;
}
此次调用后str
的状态有效,但未指定。这意味着您仍然可以为str
分配一个新值以使其恢复到有效状态,但是您无法在不调用未指定的行为(demo)的情况下输出它。有关移出状态的具体信息,请参阅this Q&A。
答案 3 :(得分:3)
std::move
只是将您的对象转换为右值引用。由于您的函数需要引用并且只是对它执行某些操作,因此此处不会使用所有权,因此您的字符串仍处于有效状态并且可以安全使用。
我不建议在您的代码中使用它,因为它会产生误导,因为很多人会认为您的字符串无效,因为取得所有权是rvalue引用的主要用途,因此std::move
。
如果您真的需要以这种方式调用此函数,我建议您写一下:
std::string myString{"a string"};
// leave a comment here to explain what you are doing.
f(static_cast<std::string&&>(myString));
但请注意,如果函数f
取值而不是引用,那么您的示例会有所不同。在这种情况下,使用std::move
或static_cast
调用它会使字符串无效。