0

I am trying to better understand how C++ constructors/initialization work. Case 2 and 5 below are confusing me.

Test case2 = Test(); Reading this, I would think it would default construct an instance of Test and copy it into case2. However, only the default constructor is invoked.

Test&& case5 = Test(); adds to my confusion. If Test() is being bound to an rvalue reference, would that not mean Test() is producing an rvalue? If that's the case, shouldn't case2 invoke the default constructor, then the move constructor? Is case 3 then producing a prvalue that we're calling std::move on (to an xvalue)? If that's the case, shouldn't case 3 and 2 behave the same (default construct an object, then use move constructor).

#include <iostream>

using namespace std;

class Test {
    int x;
    public:
        Test() : x(0) {
            cout << "DEFAULT CONSTRUCTOR CALLED" << endl;
        }
        Test(int v_x) : x(v_x) {
            cout << "PARAMETER CONSTRUCTOR CALLED" << endl;
        }
        Test(Test& other) : x(other.x) {
            cout << "COPY CONSTRUCTOR CALLED" << endl;
        }
        Test(Test&& other) : x(other.x) {
            cout << "MOVE CONSTRUCTOR CALLED" << endl;
        }
};

int main()
{
    cout << "CASE 1: " << endl;
    Test case1; // calls default constructor
    
    cout << "CASE 2: " << endl;
    Test case2 = Test(); // calls default constructor
    
    cout << "CASE 3: " << endl;
    Test case3 = std::move(Test()); // calls default constructor, then move constructor
    
    cout << "CASE 4: " << endl; 
    Test case4 = case3; // calls copy constructor
    
    cout << "CASE 5: " << endl;
    Test&& case5 = Test(); // calls default constructor

    return 0;
}

confused
  • 11
  • 2
  • Your assumptions about `Test case2 = Test();` is really close. Compilers are smart these days, so they eliminate the copy. Back before C++17, you needed a viable copy constructor, even if the copy was optimized out, 17 and after, no copy constructor required. – user4581301 Jul 05 '22 at 00:19
  • "_If that's the case, shouldn't case 3 and 2 behave the same_": Copy elision applies only if the initializer is a prvalue, which as you noted `std::move(Test())`, a xvalue, is not (while `Test()` is). For the details of copy elision (which is what you are getting confused by here) see the linked duplicate. – user17732522 Jul 05 '22 at 00:22

0 Answers0