是否可以将std :: move对象移出函数? (C ++ 11)

时间:2012-11-29 03:48:42

标签: c++ function c++11 move-semantics rvalue-reference

这个程序试图将一个字符串移出函数并用它来构造另一个字符串:

#include <iostream>
#include <string>
#include <utility>

std::string && Get_String(void);

int main(){

    std::string str{Get_String()};
    std::cout << str << std::endl;

    return 0;
}

std::string && Get_String(void){

    std::string str{"hello world"};

    return std::move(str);
}

程序编译,但执行时会出现段错误。


这是我的理由:Get_String将创建一个本地字符串。在字符串超出范围之前,需要创建并返回该字符串的副本。该副本将用于在main中构造字符串。但是,如果我将字符串移出函数,则不需要复制。

为了理解移动语义,有人可以解释为什么我在做什么,可能没有意义。是否可以将对象移出函数?


修改
如果我从:

更改函数签名,它将正确编译并运行
std::string && Get_String(void);

std::string Get_String(void);  

在这种情况下,在返回期间移动字符串是否仍然更有效?

2 个答案:

答案 0 :(得分:16)

鉴于此示例,

X foo ()
{
  X x;    
  return x;
}

保证以下行为:

  

•如果X具有可访问的副本或移动构造函数,则编译器可以   选择忽略副本。这就是所谓的(命名)返回值   优化((N)RVO),甚至在C ++ 11之前就已经指定了   大多数编译器支持。
  •否则,如果X有移动构造函数,则移动x   •否则,如果X有复制构造函数,则复制x   •否则,将发出编译时错误。

另请注意,如果返回的对象是本地非静态对象,则返回rvalue引用是错误的:

X&& foo ()
{
  X x;
  return x; // ERROR: returns reference to nonexistent object
}

右值引用是一个引用,在引用本地对象时返回它意味着你 返回对不再存在的对象的引用。是否使用std::move()不是 物质

std::move()并没有真正移动物体;它只会将左值变成右值。

答案 1 :(得分:2)

Get_String函数将rvalue引用绑定到函数本地对象。 Rvalue引用对于即将被销毁的东西很有用,但对于已被销毁的东西的左值引用也一样糟糕。

要将本地对象移出函数,只需按类类型返回:

std::string Get_String(void) {
    std::string str{"hello world"};
    return str;
}

如果编译器无法完全消除复制/移动,那么只要返回表达式为:

  • 临时或
  • 一个标识符,用于命名具有自动存储持续时间的内容(如上面的str)或
  • std::move(something)

(所以你仍然可以让return std::move(str);明确,但这里没有必要。)