C++ 可以将std::对象移出函数吗?(C+;+;11)

C++ 可以将std::对象移出函数吗?(C+;+;11),c++,function,c++11,move-semantics,rvalue-reference,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; ret

此程序尝试将字符串移出函数,并将其用于构造另一个字符串:

#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);
}

在这种情况下,在返回过程中移动字符串是否更有效?

给定此示例

X foo ()
{
  X x;    
  return x;
}
保证以下行为:

•如果
X
具有可访问的复制或移动构造函数,编译器可能会 选择删除副本。这就是所谓的(命名的)返回值 优化((N)RVO),它甚至在C++11之前就已经指定,现在是 大多数编译器都支持。
•否则,如果
X
具有移动构造函数,则移动
X

•否则,如果
X
具有复制构造函数,则复制
X

•否则,将发出编译时错误

还要注意,如果返回的对象是本地非静态对象,则返回右值引用是错误的:

X&& foo ()
{
  X x;
  return x; // ERROR: returns reference to nonexistent object
}
右值引用是一个引用,在引用本地对象时返回它意味着 返回对不再存在的对象的引用。无论是否使用
std::move()
,都不起作用 重要

std::move()
不会真正移动对象;它只将左值转换为右值。

在这个例子中

X foo ()
{
  X x;    
  return x;
}
保证以下行为:

•如果
X
具有可访问的复制或移动构造函数,编译器可能会 选择删除副本。这就是所谓的(命名的)返回值 优化((N)RVO),它甚至在C++11之前就已经指定,现在是 大多数编译器都支持。
•否则,如果
X
具有移动构造函数,则移动
X

•否则,如果
X
具有复制构造函数,则复制
X

•否则,将发出编译时错误

还要注意,如果返回的对象是本地非静态对象,则返回右值引用是错误的:

X&& foo ()
{
  X x;
  return x; // ERROR: returns reference to nonexistent object
}
右值引用是一个引用,在引用本地对象时返回它意味着 返回对不再存在的对象的引用。无论是否使用
std::move()
,都不起作用 重要


std::move()
不会真正移动对象;它只将左值转换为右值。

Get\u String
函数将右值引用绑定到函数本地对象。右值引用对于即将被销毁的东西很有用,但与左值引用对于已经被销毁的东西一样糟糕

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

std::string Get_String(void) {
    std::string str{"hello world"};
    return str;
}
如果编译器无法完全消除复制/移动,则调用方获得的返回值将使用移动构造函数而不是复制构造函数构造,只要返回表达式为:

  • 临时的,或
  • 命名具有自动存储持续时间的内容的单个标识符(如上面的
    str
    ),或
  • std::移动(某物)

(因此,您仍然可以显式地使用
返回std::move(str);
,但这里不需要它。)

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

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

std::string Get_String(void) {
    std::string str{"hello world"};
    return str;
}
如果编译器无法完全消除复制/移动,则调用方获得的返回值将使用移动构造函数而不是复制构造函数构造,只要返回表达式为:

  • 临时的,或
  • 命名具有自动存储持续时间的内容的单个标识符(如上面的
    str
    ),或
  • std::移动(某物)

(因此您仍然可以显式地使用
返回std::move(str);
,但这里不需要它。)

RVO解决了这个问题。不要通过使用
std::move
@chris禁用它,我应该按值返回,编译器将根据我正在做的事情进行优化?是的,任何现代编译器都应该删除副本。悬空引用是悬空引用;不管它是左值引用还是右值引用,RVO解决了这个问题。不要通过使用
std::move
@chris禁用它,我应该按值返回,编译器将根据我正在做的事情进行优化?是的,任何现代编译器都应该删除副本。悬空引用是悬空引用;不管它是左值还是右值引用。