如何在函数返回期间使用std :: string移动语义? [重复]

时间:2022-09-10 23:48:35

Possible Duplicate:
C++11 rvalues and move semantics confusion

可能重复:C ++ 11 rvalues并且移动语义混乱

What I think is correct is

我认为是正确的

std::string GetLine()
{
std::string str;
std::getline(std::cin, str);
return std::move(str);
}

But at this link http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html ( check the header part Returning an explicit rvalue-reference from a function)

但是在这个链接http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html(检查标题部分返回一个明确的右值引用功能)

which is #1 google search hit for move semantics shows a similar function signature as

这是#1谷歌搜索命中移动语义显示类似的功能签名

int&& GetInt()
{
int x = 0;
// code here
return std::move(x);
}

From what I read at other places && means rvalue reference so in this case its returning a reference to an object that doesn't exist.

从我在其他地方读到的&&表示右值引用,所以在这种情况下它返回对不存在的对象的引用。

So which is it?

那是哪个呢?

(Yes I know moving an int has no real benifit but the question is whether to use the return type of std::string or std::string&& in the first function. And if that is how it should be done for all types.)

(是的,我知道移动int没有真正的好处,但问题是在第一个函数中是否使用std :: string或std :: string &&的返回类型。如果这是应该对所有类型执行的方式。)

3 个解决方案

#1


29  

You are absolutely correct that the int&& GetInt() example is wrong, and is returning a reference to an object that is destroyed. However, unless I missed it, the link you posted does not actually show any code returning a reference to a local variable. Instead I see a reference to a global variable being returned, which is okay.

你绝对正确的是int && GetInt()示例是错误的,并且正在返回对被销毁对象的引用。但是,除非我错过了,否则您发布的链接实际上并未显示任何返回对本地变量的引用的代码。相反,我看到了对返回的全局变量的引用,这没关系。

Here is how you use move semantics when returning:

以下是返回时使用移动语义的方法:

std::string func()
{
    std::string rv;
    /* ... */
    return rv;
}

You generally should not use std::move() when returning an object. The reason for this is that moving is already implicitly allowed anytime RVO could occur, and using std::move() will suppress RVO. So using std::move() will never be better and will often be worse than just returning normally.

通常,在返回对象时不应使用std :: move()。这样做的原因是任何时候RVO都可以隐式允许移动,并且使用std :: move()将抑制RVO。所以使用std :: move()永远不会更好,并且通常会比正常返回更糟糕。


Again, using std::move() can be worse than simply naming the variable to be returned because it suppresses the return value optimization. The return value optimization allows for an object to be returned to the caller without needing to copy that object

同样,使用std :: move()可能比简单地命名要返回的变量更糟糕,因为它会抑制返回值优化。返回值优化允许将对象返回给调用者,而无需复制该对象

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(函数或catch子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作

— [class.copy] 12.8/31

- [class.copy] 12.8 / 31

But using std::move() prevents the return expression from being the name of the object you're returning. Instead the expression is more complicated and the language is no longer allowed to give it special handling.

但是使用std :: move()可以防止返回表达式成为您要返回的对象的名称。相反,表达式更复杂,不再允许语言对其进行特殊处理。

The reason just naming the object is not worse than using std::move() is because there's another rule that says an expression can already be treated as an rvalue without needing std::move().

命名对象的原因并不比使用std :: move()更糟糕的原因是因为有另一个规则表明表达式已经可以被视为rvalue而不需要std :: move()。

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的。

#2


7  

Answering the question, sort of: return a string. Don't move anything, but rather use (rely on) RVO:

回答这个问题,排序:返回一个字符串。不要移动任何东西,而是使用(依赖)RVO:

std::string func()
{
    std::string rv;
    /* ... */
    return rv;
}

This is how it generally should be done. You can't return an (r-value or not) reference to a temporary.

这通常应该如何完成。您不能将(r值或非r)值引用返回临时值。

#3


4  

No need to say return std::move(str); if str is a local variable: If the variable satisfies the criteria for return-value optimisation, then in a return statement the variable will bind to an rvalue reference.

无需说返回std :: move(str);如果str是局部变量:如果变量满足返回值优化的条件,则在return语句中变量将绑定到右值引用。

Also, beware that you should probably not return a reference to a local variable, neither lvalue nor rvalue reference.

另外,请注意,您可能不应该返回对局部变量的引用,既不是左值也不是右值引用。

All told, you should have:

总而言之,你应该:

int foo() { int x; /*...*/ return x; }

std::string bar() { std::string str; /*...*/ return str; }

#1


29  

You are absolutely correct that the int&& GetInt() example is wrong, and is returning a reference to an object that is destroyed. However, unless I missed it, the link you posted does not actually show any code returning a reference to a local variable. Instead I see a reference to a global variable being returned, which is okay.

你绝对正确的是int && GetInt()示例是错误的,并且正在返回对被销毁对象的引用。但是,除非我错过了,否则您发布的链接实际上并未显示任何返回对本地变量的引用的代码。相反,我看到了对返回的全局变量的引用,这没关系。

Here is how you use move semantics when returning:

以下是返回时使用移动语义的方法:

std::string func()
{
    std::string rv;
    /* ... */
    return rv;
}

You generally should not use std::move() when returning an object. The reason for this is that moving is already implicitly allowed anytime RVO could occur, and using std::move() will suppress RVO. So using std::move() will never be better and will often be worse than just returning normally.

通常,在返回对象时不应使用std :: move()。这样做的原因是任何时候RVO都可以隐式允许移动,并且使用std :: move()将抑制RVO。所以使用std :: move()永远不会更好,并且通常会比正常返回更糟糕。


Again, using std::move() can be worse than simply naming the variable to be returned because it suppresses the return value optimization. The return value optimization allows for an object to be returned to the caller without needing to copy that object

同样,使用std :: move()可能比简单地命名要返回的变量更糟糕,因为它会抑制返回值优化。返回值优化允许将对象返回给调用者,而无需复制该对象

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(函数或catch子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作

— [class.copy] 12.8/31

- [class.copy] 12.8 / 31

But using std::move() prevents the return expression from being the name of the object you're returning. Instead the expression is more complicated and the language is no longer allowed to give it special handling.

但是使用std :: move()可以防止返回表达式成为您要返回的对象的名称。相反,表达式更复杂,不再允许语言对其进行特殊处理。

The reason just naming the object is not worse than using std::move() is because there's another rule that says an expression can already be treated as an rvalue without needing std::move().

命名对象的原因并不比使用std :: move()更糟糕的原因是因为有另一个规则表明表达式已经可以被视为rvalue而不需要std :: move()。

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的。

#2


7  

Answering the question, sort of: return a string. Don't move anything, but rather use (rely on) RVO:

回答这个问题,排序:返回一个字符串。不要移动任何东西,而是使用(依赖)RVO:

std::string func()
{
    std::string rv;
    /* ... */
    return rv;
}

This is how it generally should be done. You can't return an (r-value or not) reference to a temporary.

这通常应该如何完成。您不能将(r值或非r)值引用返回临时值。

#3


4  

No need to say return std::move(str); if str is a local variable: If the variable satisfies the criteria for return-value optimisation, then in a return statement the variable will bind to an rvalue reference.

无需说返回std :: move(str);如果str是局部变量:如果变量满足返回值优化的条件,则在return语句中变量将绑定到右值引用。

Also, beware that you should probably not return a reference to a local variable, neither lvalue nor rvalue reference.

另外,请注意,您可能不应该返回对局部变量的引用,既不是左值也不是右值引用。

All told, you should have:

总而言之,你应该:

int foo() { int x; /*...*/ return x; }

std::string bar() { std::string str; /*...*/ return str; }