15

Why C++ provide a copy constructor? The assignment operator can do the same task. Is there any advantage of copy constructor over assignment operator?

Rohan Bari
  • 7,482
  • 3
  • 14
  • 34
Proton
  • 343
  • 4
  • 18
  • 6
    How would you do `Foo copy(source);` without a copy constructor? – NathanOliver Feb 23 '21 at 20:08
  • 3
    Also hard to pass by value without copy construction. – user4581301 Feb 23 '21 at 20:13
  • 3
    @NathanOliver I think the OP is asking for the difference/benefit of `Foo copy(source);` vs `Foo copy; copy = source;` – Remy Lebeau Feb 23 '21 at 20:14
  • Copy constructor could be a deep copy, while the assignment operator could be for assigning the memory address – Nick Gallimore Feb 23 '21 at 20:28
  • Does this answer your question? [Assignment operator Vs Copy constructor](https://stackoverflow.com/questions/46775047/assignment-operator-vs-copy-constructor) – xskxzr Feb 27 '21 at 05:12
  • Does this answer your question? [What's the difference between assignment operator and copy constructor?](https://stackoverflow.com/questions/11706040/whats-the-difference-between-assignment-operator-and-copy-constructor) – bytehala Mar 04 '21 at 20:29

4 Answers4

21

Stuff you can do with a copy constructor that you can't do (either easily or at all) with the assignment operator:

  1. Copy classes that don't have a default constructor. For example, if a class represents an open file, you might not be able to construct one without passing it a file name to open.

  2. Copy classes that have an expensive default constructor. Maybe the constructor allocates a lot of memory, which will then be released as soon as you use the assignment operator to copy a new state into the object.

  3. Pass an instance of the class by value. This is kind of the original purpose of the copy constructor. In C, if you pass a struct by value, the compiler just does a bitwise copy of the struct so the receiving function has a local copy that it can modify without affecting the caller. But C++ recognizes that a bitwise copy is not the best way to copy most objects, so it lets you write your own copy constructor (and the default copy behavior is different too, since class members may have custom copy constructors).

  4. Copy a class that contains references, because you can't reassign a reference after the class has already been constructed. The copy constructor and assignment operator just do different things where references are concerned. The copy constructor initializes the reference to point to the same object that the reference points to in the instance that is being copied; the assignment operator actually copies the value of the referenced object.

  5. Copy a class with const members. (Note that a class can have a default constructor but still have const members.)

Willis Blackburn
  • 8,068
  • 19
  • 36
  • 1
    Re point 4, isn't it a bad idea for a class that copy-constructs by reference to also be copy-assignable? – Joseph Sible-Reinstate Monica Feb 24 '21 at 05:06
  • 2
    Probably. I’m trying to think of an example in which you’d want to do that and not really coming up with anything. – Willis Blackburn Feb 24 '21 at 14:17
  • Re 2: You dropped an "efficiently" there, because it is certainly possible though wasteful. – Deduplicator Feb 24 '21 at 19:53
  • I tried to cover that with the "either easily or not at all" comment. It's also possible to assign classes with const members (#5) by casting the const away, or allocate an object without calling its constructor and then assign over it. It's just not a good idea. – Willis Blackburn Feb 24 '21 at 22:00
11

With or without a copy constructor, you still have to initialize a new object to a stable initial state, which the assignment operator can then update later.

While you can certainly do that without a copy constructor, having a copy constructor helps to optimize a new object's initialization, by setting it to copy another object's state up front, without requiring you to first initialize the new object to a default state and then have a separate assignment reset that state afterwards. This way, you can set the new object's state in 1 operation instead of 2 operations.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
4

Yes, the two are different. You can't always just implement your copy constructor as

Foo(const Foo& f) {
    *this = f;
}

The assignment operator assumes that you have a valid, fully constructed object. The copy constructor makes no such assumptions. This means that, depending on your class, the assignment operator may try to clear whatever data is on the object before re-initializing. Or may even repurpose the data already on the object.

scohe001
  • 15,110
  • 2
  • 31
  • 51
  • 8
    Typically, one should implement the assignment operator to use the copy constructor, not the other way around. – Remy Lebeau Feb 23 '21 at 20:15
  • Absolutely @Remy. Might be work mentioning the [Copy Swap idiom](https://stackoverflow.com/q/3279543/2602718) here actually. – scohe001 Feb 23 '21 at 20:18
  • @RemyLebeau, what if the class is abstract and I don't want to move implementation into derived classes? – Evg Feb 23 '21 at 20:30
  • An abstract class can still have constructors and assignment operators, which derived classes can call as needed. – Remy Lebeau Feb 23 '21 at 20:40
  • @RemyLebeau If I want to put all copy construction code into the base class that already has an assignment operator, I can use `*this = f;` type of constructor. However, I can't implement assignment via copy construction. The question is whether this problem has some idiomatic solution. – Evg Feb 23 '21 at 21:41
-1

Take this example.

Jack and John are twins. You could say this is Jack and that is Jack. But although John is the spitting image of Jack, he ain't no Jack.

When you use the assignment operator you can refer to the exact object in memory (returning *this) or provide some custom behavior.

When you use the copy constructor you want to create another object in memory that has a copy of the properties of the original object, but that can evolve in a different direction.

If you want a deeper answer I think this blog post is better.

Assignment is a little more tricky than initialization, because what we are essentially doing is destructing the existing object and then re-constructing it with new values. In a more complex class, you might need to free various resources and then re-allocate them using copies of the resources from the object being copied. std::unique_ptr makes our life easy here, because assigning a new instance of std::unique_ptr to an existing std::unique_ptr object with = as above (or by using reset()) first frees the old pointer, so releasing the resource is handled for us automatically (this is the same reason our class doesn’t need a destructor – when std::unique_ptr goes out of scope as our object goes out of scope, std::unique_ptr‘s destructor is called and the resource is freed automatically).

Sérgio Azevedo
  • 313
  • 1
  • 4
  • 13
  • This isn't true in C++ about the assignment operator: "exact object in memory", "two variables that point to the same memory block". – davidbak Feb 24 '21 at 17:56
  • Looks like it's been too long from my C++ days. I found this comparison interesting [copy-constructor-vs-assignment-operator-in-c](https://www.geeksforgeeks.org/copy-constructor-vs-assignment-operator-in-c/) – Sérgio Azevedo Feb 26 '21 at 16:35