3

This is what I did originally.

class A
{   public:
    A()         { std::cout << "\ndefault constructor";     }
    A(const A&) { std::cout << "\ncopy constructor";        }
    A(int)      { std::cout << "\nconversion constructor";  }
};

A a0;           // print default constructor
A a1(a0);       // print copy constructor       note : direct initialization
A a2 = a0;      // print copy constructor       note : copy initialization
A a3(123);      // print conversion constructor     note : direct initialization
A a4 = 123;     // print conversion constructor     note : copy initialization (create a temp object from int)

However, if class A is slightly modified as the following (remove const in copy constructor), why are there compile error for the final line? thank you

class A
{   public:
    A()         { std::cout << "\ndefault constructor";     }
    A(A&)       { std::cout << "\ncopy constructor";        }
    A(int)      { std::cout << "\nconversion constructor";  }
};

A a0;           // print default constructor
A a1(a0);       // print copy constructor       note : direct initialization
A a2 = a0;      // print copy constructor       note : copy initialization
A a3(123);      // print conversion constructor     note : direct initialization
//A a4 = 123;   // compile error
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
Dick Chow
  • 31
  • 2
  • 2
    temporary object will be destroyed at the line which it is created, so the compiler thinks that you will modify it when you pass it as non const reference ( there is a possiblity you will modify it when you pass by non const reference ), but modifying it is illegal since its already destroyed at that scope – Lorence Hernandez Nov 19 '16 at 05:41

2 Answers2

6
A a4 = 123;

is equivalent to

A a4 = A(123); // The RHS is a temporary A object.

That works for the first case since there is a constructor that takes a A const& as the argument type.

That does not work if the argument type is A&. A temporary object can be used when the argument type is A const&, not when it is A&.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

For the case A a4 = 123;, when object “a4” is being constructed, the statement

A a4 = 123;

is broken down by the compiler as

A a4 = A(123);

In above statement, one argument constructor i.e. A(int) is used to convert integer value “123” to a temporary object & that temporary object is copied to the object “a4” using copy constructor. C++ does not allow to pass temporary objects by non-const reference because temporary objects are rvalue that can't be bound to reference to non-const.

So, generically, If you're not passing your argument with a const qualifier, then you can't create copies of const objects.

One more similar example for better understanding:

class Test
{
   /* Class data members */
public:
   Test(Test &t) { /* Copy data members from t*/}
   Test()        { /* Initialize data members */ }
};

Test fun()
{
    cout << "fun() Called\n";
    Test t;
    return t;
}
int main()
{
    Test t1;
    Test t2 = fun();  //compilation error with non-const copy constructor
    return 0;
}

$g++ -o main *.cpp
main.cpp: In function ‘int main()’:
main.cpp:22:18: error: cannot bind non-const lvalue reference of type ‘Test&’ to an rvalue of type ‘Test’
     Test t2 = fun();
               ~~~^~
main.cpp:8:4: note:   initializing argument 1 of ‘Test::Test(Test&)’
    Test(Test &t) { /* Copy data members from t*/}
    ^~~~
Saral Garg
  • 132
  • 7