4

When I was reading:

What's the difference between assignment operator and copy constructor?

here: What's the difference between assignment operator and copy constructor?

The following example was shown:

A aa;
A a = aa;  //copy constructor

vs:

A aa;
A a;
a = aa;  // assignment operator

and my question is, why we need the assignment operator at all? I mean that it will be more efficient to use the copy constructor in this case while it does the same job.

could someone give a real-world example of the use of assignment operator where that can't be replaced by the copy constructor?

  • 1
    *I mean that it will be more efficient to use the copy constructor in this case while it does the same job.* -- Your class should work regardless of what the user chooses to do. *could someone give a real-world example of the use of assignment operator where that can't be replaced by the copy constructor?* -- `int x = 10; int y = 4; if (something) x = y;` – PaulMcKenzie May 25 '20 at 07:19
  • let say you are using pool of object that that allready created and you need to copy theam – yaodav May 25 '20 at 07:21
  • Removing an element from the middle of an array or vector? How would you "shift" the other elements without assignment? – Daniel Langr May 25 '20 at 07:22
  • @PaulMcKenzie Why not `int y = 4; int x = (something) ? y : 10;` ? – Jasper Kent May 25 '20 at 07:22
  • Why not walk 25 miles instead of driving? That's basically what this is boiling down to. It makes no sense really in writing code in knots like that, when a simple reassignment can be done. – PaulMcKenzie May 25 '20 at 07:23
  • @DanielLangr how is your example related? when removing an element I simply delete it via a function.... –  May 25 '20 at 07:25
  • @PaulMcKenzie but does Jasper's solution use copy operator in this case? –  May 25 '20 at 07:25
  • Basically, you can replace an _assignment_ by _destruction_ followed by _copy/move construction_. I can see two problems here. First, if the constructor throws, you end up with non-existing object. If, this happens, e.g., within array, you are in big troubles. And, the second approach will be much less efficient in many practical cases. – Daniel Langr May 25 '20 at 07:26
  • @smith_brown -- Let's say you are writing a library, and you have no idea who will use it. So you now will deliver a broken library to those users. Believe me, you *will* get complaints. – PaulMcKenzie May 25 '20 at 07:26
  • @smith_brown With which function? How would such a function be implemented without the use of assignment operator? – Daniel Langr May 25 '20 at 07:28
  • @PaulMcKenzie but what's the difference between 'int x = 10; int y = 4; if (something) x = y;' and 'int y = 4; int x = (something) ? y : 10;', does the second use copy constructor? –  May 25 '20 at 07:30
  • @smith_brown The difference is, for example, that in the first case, `if` can be placed to an entirely different scope (if `x` is accessible there). Such as to lambda, thread code, etc. – Daniel Langr May 25 '20 at 07:31
  • And what if the creation of `x` (let's say it isn't a simple `int`) is an expensive operation? Why would you needlessly create objects over and over again? – PaulMcKenzie May 25 '20 at 07:31
  • Also, it is going to be very difficult and honestly, a waste of time trying to pinpoint exactly where or when a copy or assignment is going to be invoked. That is almost always up to the compiler as to when, where, or if those operations are invoked. A good compiler could just eliminate copying and assignment due to optimizing the code. So that's one huge reason why you need to supply both copy and assignment operations, and trying to write end-user code to avoid either copying or assignment will many times end up as a futile attempt. – PaulMcKenzie May 25 '20 at 07:39
  • BTW, note that an assignment operator is sometimes implemented via copy/move construction (see _copy-and-swap idiom_). However, this is not always the best solution in terms of performance. Very basic example — if an assigned-to vector's capacity is greater or equal to the assigned-from vector size, there is no need for new allocation. Copy-and-swap would always delete the original buffer and allocate again, which is unnecessary. – Daniel Langr May 25 '20 at 07:41

4 Answers4

2

You need assignments when you want to change a value after it has already been constructed. For example:

  • change a value that is already stored in a std::map
  • change the nth value inside a std::vector
  • change the value of a variable outside a loop
  • change the value of an output parameter provided as a pointer or reference
  • ...

The list could really go on almost endlessly. But in your example it is true that one could simply avoid the use of an assignment.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
0

The copy constructor is called only once - at the time of initialisation of object. When the copy constructor is called, it allocates a new block of memory to the variable and then assigns it the other object .

But in assignment constructor, only the values of fields in one object are copied to the other object and the same memory is allocated when assignment constructor is called. That's the main difference between the copy constructor and assignment constructor. copy constructor allocates separate memory to both the objects, i.e. the newly created target object and the source object. The assignment operator allocates the same memory location to the newly created target object as well as the source object.

The copy constructor is called just once in object lifetime and that's if it's initialised during its declaration. Every other time you assign other object to it, the assignment constructor will be called.

Abhishek Bhagate
  • 5,583
  • 3
  • 15
  • 32
  • your answer is wrong, "But in assignment constructor, only the values of fields in one object are copied to the other object. No new memory is allocated when assignment constructor is called" –  May 25 '20 at 07:28
  • 1
    @smith_brown -- For trivially copyable types, no new memory is allocated, and the compiler does an efficient copy (probably using `memcpy`) operation. – PaulMcKenzie May 25 '20 at 07:33
  • 3
    I would suggest using some more standard language. Constructors do not allocate object storage (they need the storage to be already allocated). Also, we don't have any _assignment constructors_ in C++. – Daniel Langr May 25 '20 at 07:34
0

Yes there is a famous one, where assignment operator cannot be replaced by copy constructor:

 std::vector <int> f();
 void g(){
     decltype(auto) v = f() = f();
     v.push_back(10); //boum undefined behaviour.
        //without the non ref qualified copy assignment operator you
        //could not have the pleasure to have undiscoverable UB in your code.
     }

Non ref qualified assignment operators and pre-increment and pre-decrement iterators operators are the best opportunities offered by the standard library to produce dangling references.

Oliv
  • 17,610
  • 1
  • 29
  • 72
0

Any copy assignment could theoretically be replaced with a call to the destructor followed by a call to the copy constructor, as the constructor is not responsible for allocating the memory for the new instance. You can actually call the constructor without allocating any memory using the placement new operator.

But, the copy assignment is still interesting over the copy constructor, and your assumption that the copy constructor is more performant is false.

The big difference between copy assignment and constructor is that in assignment you can rely on the fact that the memory is already initialised. In the best case, this pre-initialisation does not offer any benefit and the copy constructor is as performant as the copy assignment. In other cases, copy assignment benefits from it and are more performant than the constructor.

And you can add the cost of the call to the destructor and the copy constructor becomes even less interesting over the assignment.

Nicolas Dusart
  • 1,867
  • 18
  • 26