可能重复:
C++11 右值和移动语义混淆
我认为正确的是
std::string GetLine()
{
std::string str;
std::getline(std::cin, str);
return std::move(str);
}
但是在这个链接http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html (检查标题部分 Returning an explicit rvalue-reference from a function)
在谷歌搜索中排名第一的移动语义显示了与
类似的函数签名int&& GetInt()
{
int x = 0;
// code here
return std::move(x);
}
根据我在其他地方读到的 && 意思是右值 reference 所以在这种情况下它返回对不存在的对象的引用。
那是什么?
(是的,我知道移动一个 int 没有真正的好处,但问题是是否在第一个函数中使用 std::string 或 std::string&& 的返回类型。如果这是对所有类型应该如何完成。 )
您完全正确,
int&& GetInt()
示例是错误的,并且正在返回对已销毁对象的引用。但是,除非我错过了它,否则您发布的链接实际上并未显示任何代码返回对 local 变量的引用。相反,我看到返回了对 global 变量的引用,这没关系。
返回时如何使用移动语义:
std::string func()
{
std::string rv;
/* ... */
return rv;
}
返回对象时通常不应使用
std::move()
。这样做的原因是,只要 RVO 可能发生,就已经隐含地允许移动,并且使用 std::move()
将抑制 RVO。所以使用std::move()
永远不会比正常返回更好,而且通常会更糟。
同样,使用
std::move()
可能比简单地命名要返回的变量更糟糕,因为它抑制了返回值优化。返回值优化允许将对象返回给调用者而无需复制该对象
在具有类返回类型的函数中的
语句中,当 该表达式是非易失性自动对象的名称(其他 比函数或 catch 子句参数)具有相同的 cv-非限定类型作为函数返回类型,复制/移动 可以通过直接构造自动对象来省略操作 进入函数的返回值return
— [class.copy] 12.8/31
但是使用
std::move()
可以防止返回表达式是 你要返回的对象的名称。相反,表达式更复杂,语言不再允许对其进行特殊处理。
仅仅命名对象并不比使用
std::move()
差的原因是因为有另一个规则说表达式已经可以被视为右值而不需要 std::move()
.
当复制操作的省略标准被满足或将被 满足除了源对象是函数参数的事实, 并且要复制的对象由左值重载指定 首先执行为副本选择构造函数的决议 就好像对象是由右值指定的一样。
回答问题,有点像:返回一个
string
。不要move
任何东西,而是使用(依赖)RVO:
std::string func()
{
std::string rv;
/* ... */
return rv;
}
通常应该这样做。你不能返回一个(r-value or not)对临时的引用。
如果
return std::move(str);
是局部变量,则无需说 str
:如果变量满足返回值优化的条件,则在 return
语句中,变量将绑定到右值引用。
此外,请注意您可能不应该返回对局部变量的引用,无论是左值还是右值引用。
总而言之,你应该:
int foo() { int x; /*...*/ return x; }
std::string bar() { std::string str; /*...*/ return str; }