如果我将一个本地对象移动到一个函数中,它之后是否仍然有效?

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::movestatic_cast 调用它会使字符串无效。