class A {
int x;
public:
A() { cout << "\t A() \n"; }
A(int _x): x(_x) { cout << "\t A(int) \n"; }
A(const A& other): x(other.x) { cout << "\t A(const A&) \n"; }
A(A&& other): x(std::move(other.x)) { cout << "\t A(A&&) \n"; }
A& operator=(const A& other) { x = other.x; cout << "\t operator=() \n"; return *this; }
};
void func_1(A obj) {
cout << "func_1\n";
}
A func_7(const A& obj) {
cout << "func_7\n";
return obj;
}
int main() {
A obj_1; // stdout: "A()" [OK]
A obj_2 = 10; // stdout: "A(int)" [OK]
A obj_3 = obj_2; // stdout: "A(const A&)" [OK]
A obj_4 = std::move(obj_3); // stdout: "A(A&&)" [OK]
obj_4 = obj_2; // stdout: "operator=()" [OK]
func_1(obj_1); // stdout: "A(const A&) \n func_1" [OK]
func_1(A(5)); // stdout: "A(int) \n func_1" [!?] Copy constructor?
func_1(5); // stdout: "A(int) \n func_1" [!?] Copy constructor?
A obj_7 = func_7(obj_2); // stdout: "func_7 \n A(const A&)" [!?] Copy constructor?
return 0;
}
For func_1(A(5));
, I expected the output to be A(int) \n A(const A&) \n func_1
because we are passing A(5)
by value so the passed object should be copied to the parameter. Similarly for func_1(5);
.
For A obj_7 = func_7(obj_2);
, I expected the output to be func_7 \n A(const A&) \n A(const A&)
because we are returning an object so that object should be copied on the stack first and then the copy constructor will be used to declare obj_7
using the returned object.
Am I missing something here? I am aware of the return value optimization, but I don't think that will apply in both the functions that we have here.
For func_1(A(5));, I expected the output to be A(int) \n A(const A&) \n func_1 because we are passing A(5) by value so the passed object should be copied to the parameter.
You expected wrongly. A(5)
is a prvalue of the same type, so the temporary object will not be materialised, and its initialiser is instead used to initialise the parameter that would have been initialised by the non-materialised temporary.
Similarly for func_1(5);.
The class has an implicit converting constructor that accepts an integer. You pass an integer; the converting constructor is used to initialise the parameter.
For A obj_7 = func_7(obj_2);, I expected the output to be func_7 \n A(const A&) \n A(const A&) because we are returning an object so that object should be copied on the stack first and then the copy constructor will be used to declare obj_7 using the returned object.
The reason for this is similar as the first case. The function call is a prvalue.