cibercitizen1
cibercitizen1

Reputation: 21496

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

Upvotes: 4

Views: 238

Answers (6)

user2100815
user2100815

Reputation:

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.

Upvotes: 4

Robᵩ
Robᵩ

Reputation: 168626

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;
    }
}

Upvotes: 1

Puppy
Puppy

Reputation: 146930

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.

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254471

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.

Upvotes: 2

J&#246;rgen Sigvardsson
J&#246;rgen Sigvardsson

Reputation: 4887

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

Upvotes: 1

Fred Larson
Fred Larson

Reputation: 62073

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

Upvotes: 6

Related Questions