简体   繁体   中英

Copy constructor not used during pass by value in C++

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.

In the case of func_1(A(5)); , the copy ctor won't be called since A(5) is an rvalue (aka a temporary). the copy ctor is only called when the value on the right-hand side is an lvalue (aka a value with a dedicated memory location).

And in the case of A obj_7 = func_7(obj_2); , the copy ctor will only be invoked once for constructing obj_7 . It won't be called when you pass obj_2 as an lvalue reference to func_7 . The parameter of func_7 is a reference. Not a new object. So no call to copy ctor required

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