如果我将一个本地对象移动到一个函数中,它之后是否仍然有效?
If I move a local object into a function, will it still be valid afterward?
因此,这提供了预期的输出:
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;
}
A string plus extra
也就是我在Ideone上运行的时候是可以的,但是是UB吗?在调用 f
之前和之后添加额外的字符串初始化并没有改变任何东西。
std::move
不移动任何东西。 它表示一个对象可以通过转换“从 移动”它对 rvalue.
的参数
您的代码有效,没有执行任何移动操作。
如果你移动构造另一个来自s
。移动构造函数执行实际的移动操作。
示例:
std::vector<std::string> sv;
void f(std::string&& s)
{
s += " plus extra";
sv.push_back(std::move(s)); // move s (str) into a new object
}
int main(void)
{
std::string str = "A string";
f(std::move(str));
std::cout << str << std::endl; // output: empty string
std::cout << sv.back() << std::endl; // output: "A string plus extra"
return 0;
}
有效,不是UB。
这也是可怕的混淆代码。 std::move(s)
只不过是对右值的强制转换。它本身实际上根本不会生成 any 代码。它的唯一目的是将左值转换为右值,以便客户端代码可以重载 lvalue/rvalue 表达式(在本例中为 string
)。
对于这种情况,您应该通过左值引用传递:
void f(std::string& s)
{
s += " plus extra";
}
...
f( str );
或者,按值传递并 return 一个新字符串:
std::string f(std::string s)
{
s += " plus extra";
return s;
}
...
str = f( std::move(str) );
代码有效,因为没有执行实际移动。以下是如何使其无效:
string f(std::string&& s) {
std::string res(std::move(s));
res += " plus extra";
return res;
}
此调用后 str
的状态将是有效的,但未指定。这意味着您仍然可以为 str
分配一个新值以使其恢复有效状态,但是如果不调用未指定的行为您将无法输出它(demo). See this Q&A 用于移动的细节-来自州。
std::move
只是将您的对象转换为右值引用。由于您的函数获取引用并对其进行一些处理,因此此处没有所有权,因此您的字符串仍处于有效状态并且可以安全使用。
我不建议在您的代码中使用它,因为它具有误导性,因为很多人会认为您的字符串无效,因为获取所有权是右值引用的主要用途,因此 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
调用它会使字符串无效。
因此,这提供了预期的输出:
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;
}
A string plus extra
也就是我在Ideone上运行的时候是可以的,但是是UB吗?在调用 f
之前和之后添加额外的字符串初始化并没有改变任何东西。
std::move
不移动任何东西。 它表示一个对象可以通过转换“从 移动”它对 rvalue.
您的代码有效,没有执行任何移动操作。
如果你移动构造另一个来自s
。移动构造函数执行实际的移动操作。
示例:
std::vector<std::string> sv;
void f(std::string&& s)
{
s += " plus extra";
sv.push_back(std::move(s)); // move s (str) into a new object
}
int main(void)
{
std::string str = "A string";
f(std::move(str));
std::cout << str << std::endl; // output: empty string
std::cout << sv.back() << std::endl; // output: "A string plus extra"
return 0;
}
有效,不是UB。
这也是可怕的混淆代码。 std::move(s)
只不过是对右值的强制转换。它本身实际上根本不会生成 any 代码。它的唯一目的是将左值转换为右值,以便客户端代码可以重载 lvalue/rvalue 表达式(在本例中为 string
)。
对于这种情况,您应该通过左值引用传递:
void f(std::string& s)
{
s += " plus extra";
}
...
f( str );
或者,按值传递并 return 一个新字符串:
std::string f(std::string s)
{
s += " plus extra";
return s;
}
...
str = f( std::move(str) );
代码有效,因为没有执行实际移动。以下是如何使其无效:
string f(std::string&& s) {
std::string res(std::move(s));
res += " plus extra";
return res;
}
此调用后 str
的状态将是有效的,但未指定。这意味着您仍然可以为 str
分配一个新值以使其恢复有效状态,但是如果不调用未指定的行为您将无法输出它(demo). See this Q&A 用于移动的细节-来自州。
std::move
只是将您的对象转换为右值引用。由于您的函数获取引用并对其进行一些处理,因此此处没有所有权,因此您的字符串仍处于有效状态并且可以安全使用。
我不建议在您的代码中使用它,因为它具有误导性,因为很多人会认为您的字符串无效,因为获取所有权是右值引用的主要用途,因此 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
调用它会使字符串无效。