Determine which copy constructors are invoked in C ++ code.

I wrote a simple C ++ class example with 1 constructor without parameters, 1 pair constructor, 2 copy constructors, 1 assignment operator and 1 plus operator.

class Complex { protected: float real, img; public: Complex () : real(0), img(0) { cout << "Default constructor\n"; } Complex (float a, float b) { cout << "Param constructor" << a << " " << b << endl; real = a; img = b; } // 2 copy constructors Complex( const Complex& other ) { cout << "1st copy constructor " << other.real << " " << other.img << endl; real = other.real; img = other.img; } Complex( Complex& other ) { cout << "2nd copy constructor " << other.real << " " << other.img << endl; real = other.real; img = other.img; } // assignment overloading operator void operator= (const Complex& other) { cout << "assignment operator " << other.real << " " << other.img << endl; real = other.real; img = other.img; } // plus overloading operator Complex operator+ (const Complex& other) { cout << "plus operator " << other.real << " " << other.img << endl; float a = real + other.real; float b = img + other.img; return Complex(a, b); } float getReal () { return real; } float getImg () { return img; } }; 

I used this class mainly like this:

 int main() { Complex a(1,5); Complex b(5,7); Complex c = a+b; // Statement 1 system("pause"); return 0; } 

The result is printed as:

 Param constructor 1 5 Param constructor 5 7 plus operator 5 7 Param constructor 6 12 

I think the copy constructor should be used in Statement 1, but I really don't know which one is being called. Please tell me who and why? Many thanks

+7
source share
1 answer

The compiler returns the call (in fact, two calls) to the copy constructor. This is allowed (but not necessary!) In accordance with paragraph 12.8 / 31 of the C ++ 11 standard, even if the constructor or destructor has side effects:

When certain criteria are met, the implementation allows you to omit the copy / move construct of the object class , even if the constructor selected for the copy / move operation and / or the destructor for the object has side effects . [..] This permission of copy / move operations, called copying, is allowed in the following circumstances (can be combined to eliminate multiple copies):

- in the return expression in a function with the type of the returned class, when the expression is the name of a non-volatile automatic object (except for the function or parameter catch-clause) with the same cv-unqualified type as the returned type of the function, the copy / move operation can be omitted when building an automatic object directly in function returns value

[...]

- if the temporary object of the class that was not attached to the link (12.2) is copied / moved to the object of the class with the same cv-unqualified type, the copy / move operation can be omitted from building the temporary object directly to the target of the missed copy / move

If the compiler has not moved away from the calls to the copy constructor, then the first one will be selected twice, i.e. the one that has the following signature:

 Complex( const Complex& other ) 

The reason is that:

  • The value returned by operator + is copied from the temporary ( Complex(a, b) ), and only lvalue references to const can bind to temporary ones. Everything would be different if operator + were written like this:

     Complex operator+ (const Complex& other) { // ... Complex c(a, b); return c; } 

    In this case, the second copy constructor will be called, since c not const -qualified and is an lvalue, so it can be bound to an lvalue reference for not const ;

  • The c object in main() copied from rvalue (the value returned by operator + is also temporary). This is true, regardless of how operator + returns its Complex object, as long as it returns it by value. Therefore, the first copy constructor will be selected if copying is not performed.

If you use GCC and want to test this behavior, try setting the -fno-elide-constructors flag (Clang supports it too, but version 3.2 has an error, and I don’t know if it was fixed).

+9
source

All Articles