Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why C++ copy constructor must use const object?

I understand that when we define a class copy constructor of the class is necessary as Rule of three states. I also notice that the argument of the copy constructor is usually const as the following codes illustrate:

class ABC {
public:
    int a;
    int b;
    ABC(const ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

My question is what would happen if the argument of the copy constructor is not const:

class ABC
{
    public:
    int a;
    int b;
    ABC(ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

I understand that in some cases if the argument of the copy constructor is const then the second implementation would fail. Also if the argument of the copy constructor is const then the object to be copied will not change its content during the process. However, I do notice that some people still use the second implementation rather than the first one. Are there any reasons that the second implementation is preferred?

like image 669
feelfree Avatar asked Jun 06 '13 07:06

feelfree


People also ask

What is the requirement of copy constructor?

A user-defined copy constructor is generally needed when an object owns pointers or non-shareable references, such as to a file, in which case a destructor and an assignment operator should also be written (see Rule of three).

Should move constructor be const?

A move constructor should normally take a non-const reference. If it were possible to move from a const object it would usually imply that it was as efficient to copy an object as it was to "move" from it. At this point there is normally no benefit to having a move constructor.

Can we pass pointer to copy constructor?

You can write any constructor you want, and it can take a pointer if you want it to, but it won't be a "copy constructor".

Can a constructor be const?

Constructors may be declared as inline , explicit , friend , or constexpr . A constructor can initialize an object that has been declared as const , volatile or const volatile . The object becomes const after the constructor completes.


Video Answer


4 Answers

  • Logically, it should make no sense to modify an object of which you just want to make a copy, though sometimes it may have some sense, like a situation where you'd like to store the number of time this object has been copied. But this could work with a mutable member variable that stores this information, and can be modified even for a const object (and the second point will justify this approach)

  • You would like to be able to create copy of const objects. But if you're not passing your argument with a const qualifier, then you can't create copies of const objects...

  • You couldn't create copies from temporary reference, because temporary objects are rvalue, and can't be bound to reference to non-const. For a more detailed explanation, I suggest Herb Sutter's article on the matter

like image 173
JBL Avatar answered Oct 19 '22 15:10

JBL


The last thing any consumer of your class would expect is a copy constructor that changed the object that was copied! Therefore, you should always mark as const.

like image 44
Bathsheba Avatar answered Oct 19 '22 16:10

Bathsheba


There are two reasons that const may be needed here:

  1. It ensures that you don't accidentally "damage" the original when making the copy - this is a good thing, because you don't really want your original object to be changed when making a copy of it!
  2. You can pass in something other than a basic object - since the constructor takes a reference, if it's not an object itself - say for example an expression.

To exemplify the second case:

 class ABC
    {
       public:
           int a;
           int b;
       ABC(const ABC &other)
       { 
         a = other.a;
         b = other.b;
       }
       ABC operator+(const ABC &other)
       {
           ABC res;
           res.a = a + other.a;
           res.b = b + other.b;
           return res;
       }
    }

  ...
  ABC A;
  a.a = 1;
  a.b = 2;
  ABC B(a+a);

This won't compile if the constructor is ABC(ABC &other), since a+a is a temporary object of type ABC. But if it's ABC(const ABC &other), we can use the temporary result of a calculation and still pass it in as a reference.

like image 12
Mats Petersson Avatar answered Oct 19 '22 15:10

Mats Petersson


As several other answers point out, a copy constructor that modified its argument would be an unpleasant surprise. That is not, however, the only problem. Copy constructors are sometimes used with arguments that are temporaries. (Example: return from function.) And non-const references to temporaries don't fly, as explained elsewhere on SO.

like image 6
Andrew Lazarus Avatar answered Oct 19 '22 16:10

Andrew Lazarus