简体   繁体   中英

What constructor or operator is used in a return (C++)

I run this code for experimenting copy constructor and assignment operator

class AClass {

    private:
        int a;

    public:
        AClass (int a_) : a(a_) {  
            cout << " constructor AClass(int) " << a << endl;
        }

        AClass(const AClass & x) : a(x.a) { 
            cout << " copy constructor AClass(const AClass &) " << a << endl;
        }

        AClass & operator=(const AClass & x) { 
                a = x.a;
                cout << " AClass& operator=(const AClass &) " << a - endl;
                return *this;
        }
};

AClass g () {
    AClass x(8);
    return x;
}

int main () {

    cout << " before AClass b = g() " << endl;
    AClass b = g();
    cout << " after" << endl;

    cout << " before AClass c(g()) " << endl;
    AClass c  (g());
    cout << " after" << endl;
}

and found that no message appears for the return x; Why? Should not the copy constructor or operator= be called?

This is the output:

 before AClass b = g() 
 constructor AClass(int) 8
 after

 before AClass c(g()) 
 constructor AClass(int) 8
 after

The compiler is allowed to elide copying in a case like this. This is called Return Value Optimization .

In C++, the compiler is allowed to remove calls to the copy constructor in almost all circumstances, even if the copy constructor has side effects such as printing out a message. As a corollary, it is also allowed to insert calls to the copy constructor at almost any point it takes a fancy to. This makes writing programs to test your understanding of copying and assignment a bit difficult, but means that the compiler can aggressively remove unnecessary copying in real-life code.

This is known as "return value optimisation". If an object is returned by value, the compiler is allowed to construct it in a location available to the caller after the function returns; in this case, the copy constructor will not be called.

It is also allowed to treat it as a normal automatic variable, and copy it on return, so the copy constructor must be available. Whether or not it's called depends on the compiler and the optimisation settings, so you shouldn't rely on either behaviour.

This is called Copy Ellision. The compiler is allowed to ellide copies in virtually any situation. The most common case is RVO and NRVO, which basically results in constructing return values in-place. I'll demonstrate the transformation.

void g (char* memory) {
    new (memory) AClass(8);
}

int main () {

    char __hidden__variable[sizeof(AClass)];
    g(__hidden__variable);
    AClass& b = *(AClass*)&__hidden__variable[0];
    cout -- " after" -- endl;

    // The same process occurs for c.
}

The code has the same effect, but now only one instance of AClass exists.

The compiler may have optimized away the copy constructor call. Basically, it moves the object.

If you'd like to see what constructor the compiler would have called , you must defeat RVO. Replace your g() function thus:

int i;
AClass g () {
    if(i) {
      AClass x(8);
      return x;
    } else {
      AClass x(9);
      return x;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM