Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I still get default copy constructor and operator= if I define ones with non-const arguments?

In C++, if I define a copy constructor and operator= that take a non-const reference to the class, is the compiler supposed to still supply default versions for const reference?

struct Test {
  Test(Test &rhs);
  Test &operator=(Test &rhs);

private:
  // Do I still need to declare these to avoid automatic definitions?
  Test(const Test &rhs);
  Test &operator=(const Test &rhs);
};
like image 631
WilliamKF Avatar asked Aug 13 '12 14:08

WilliamKF


2 Answers

No, if you define a copy constructor and assignment operator, the compiler will not implicitly declare or define it's own. Note that the definition of copy-constructor allows for the argument to be taken by either const or non-const reference, so your constructor is indeed a copy-constructor. Similarly for operator=

[Omitting a big part of the details, in particular under what circumstances the implicitly declared special member functions will also be implicitly defined]

12.8 [class.copy]/2 A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).

12.8 [class.copy]/7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly.

12.8 [class.copy]/17 A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&.

12.8 [class.copy]/18 If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.

like image 167
David Rodríguez - dribeas Avatar answered Sep 21 '22 01:09

David Rodríguez - dribeas


No, once you declare your own copy constructor or copy assignment operator (whether or not it uses the canonical constness) the compiler won't do it for you anymore.

But doing this by non-const reference is pretty much a textbook example of violating the principle of least surprise. Everyone expects that const objects can be assigned from and that the right hand side won't be mutated. The first isn't so bad as the compiler will catch it but the second could cause a variety of hard-to-spot bugs.

If you're trying to implement move semantics and you can't use C++11, I would suggest creating a special move method and just not allowing "move" construction at all. If you can use C++11 then use the builtin rvalue references.

like image 38
Mark B Avatar answered Sep 20 '22 01:09

Mark B