Question

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);
};
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top