这个程序试图将一个字符串移出函数并用它来构造另一个字符串:
#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);
在这种情况下,在返回期间移动字符串是否仍然更有效?
答案 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);
明确,但这里没有必要。)