When does returning a value outside of a function uses move vs copy?

橙三吉。 提交于 2019-12-08 16:44:07

问题


After reading this question. I created this small little test:

class A{
public:
    A(){}
    A(const A&){printf("copy\n");}
    A(A&&){printf("move\n");}

    static A f(){
        A a;
        return a;}

    static A g(){
        A a;
        return (a);}//could be return *&a; too.

    static A h(){
        A a;
        return true?a:a;}

 };

The result is (without RVO and NRVO):

  • f uses move
  • g uses move
  • h uses copy

As far as I know the rules used to decide whether to use copy or move are described in 12.8.32:

  • 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. ...

Which refers to the rules of 12.8.31: (I only show the relevant part)

  • 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 cvunqualified 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
  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

Following these rules I understand what happens for f and h:

  • The copy in f is eligible for elision so it is moved. (cf. the bold part)
  • The copy in h is not eligible for elision so it is copied.

What about g?

To me it looks really like h. I am returning an expression which is not the name of an automatic object and as such I thought it would be copied however it is moved. What is going on here?


回答1:


In most cases there is no difference in writing a or (a). The relevant part of the spec is §5.1p6 (emphasis mine):

A parenthesized expression is a primary expression whose type and value are identical to those of the enclosed expression. The presence of parentheses does not affect whether the expression is an lvalue. The parenthesized expression can be used in exactly the same contexts as those where the enclosed expression can be used, and with the same meaning, except as otherwise indicated.

Hence, the same reasoning applies to the return value of your function g as you have given for f.


In the upcomming standard C++14 this has been clarified §12.8p32 (emphasis mine):

When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.


For those who want to know, when the parentheses matter, here is an example:

namespace N {
struct S { };

  void f(S);

}

void g() {
  N::S s;
  f(s); // OK: calls N::f
  (f)(s); // error: N::f not considered; parentheses
          // prevent argument-dependent lookup
}



回答2:


Note that if you declare

const A a;

in your examples, they will all copy. Section 12.8 of the standard says "overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue," but if a is const, that will be a const rvalue, which doesn't match the move constructor.



来源:https://stackoverflow.com/questions/23914289/when-does-returning-a-value-outside-of-a-function-uses-move-vs-copy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!