3

Considering the advantages of copy-and-swap idiom...

Why do we still need copy-assignment operator accepting references as the mainstream?

class T {
public:

    // 1: Why still commonly this?
    T& operator=(const T& rhs);

    // 2: Why not mostly that?
    T& operator=(T rhs);
}

There are answers suggesting to use the latter (here and here).

However, most of the SO examples are still around pass-by-reference operator=.

Even consolidated C++ FAQ points out (yes, it's about const, but...):

A class Fred’s copy constructor and assignment operator should have const in the parameter: respectively Fred::Fred(const Fred&) and Fred& Fred::operator=(const Fred&)

Obviously, copy-and-swap is implementable via pass-by-reference - it is just unnecessary if copy is to be made anyway. One may also want to avoid copying immediately on call (perform it conditionally in the body) - isn't that the less frequent case (possibly premature optimization) then?

Shouldn't copy-and-swap with pass-by-value assignment be the default approach?

uvsmtid
  • 3,771
  • 3
  • 33
  • 55

3 Answers3

2

Pass by reference is for avoiding unnecessary copy when you need faster executions, and pass by a const reference is when you want to pass it fast and read-only. And pass by copy is when you want to copy the object to be able to manipulate it in the course of the execution/implementation of your function.

Hack06
  • 864
  • 1
  • 8
  • 18
  • 1
    It's logical explanation of the mechanisms, but it's not clear how copy-assignment operator benefits from other options if it is supposed to copy and assign anyway. This answer is more about differences between the mechanisms than "copy-and-swap with assignment by value" case in the question. – uvsmtid May 03 '20 at 12:52
  • I think it's pretty logical to give the developers a freedom on deciding how to pass a variable: copy and do whatever you want, take it but don't modify, or take it and do whatever you want. – Hack06 May 03 '20 at 12:54
  • I agree with giving the options in general (for all situations out there). But I don't see how it makes sense to exercise every option in this specific use case. Do I even need to consider other options before picking the single one for copy-assignment operator (pass by value with copy-and-swap) every time in the first iteration? Any other option seems like optimization. – uvsmtid May 03 '20 at 13:04
1

More than it creates spurious non useful copies, second option may not work on every class as copying may be deleted.

First option have many, if not all, advantages : no copy, read-only semantic, always available.

Jean-Baptiste Yunès
  • 30,872
  • 2
  • 40
  • 66
  • I think that it's an exotic case when _assignment_ operator exists for read-only-semantics - what does it mean to assign to a read-only object? Also, if we delete copy-constructor, what are we implementing in copy-assignment? I don't exclude some special cases, but it doesn't seem like default one either. – uvsmtid May 03 '20 at 13:18
  • it may be a mistake, I would have mean something about the `const` not about mutability. – Jean-Baptiste Yunès May 03 '20 at 13:22
1

I was pointed to the valuable hint:

For example, ever wonder why high performance / often used std::types like std::vector and std::string don't use copy/swap? | Howard Hinnant

Everything I found against copy-on-swap was about optimization (avoid copy, re-purpose lhs):

  • Obviously, self-assignment is noop.
  • Another common possibility happens in (STL) container when lhs has space for rhs:

    class container<T> {
    public:
        // If passed by value, created copy would unconditionally increase capacity:
        T& operator=(const container<T>& rhs) {
           // ...
           if (this->capacity() >= rhs.size()) {
               // reuse capacity ...
           } else {
               // increase capacity ...
           }
        }
    }
    

    Notice that the hint also mentions (STL) containers.

The trade-off for operator= is:

  • by value + copy-and-swap: simplifies (saves human time) with strong exception guarantees
  • by reference: allows optimization (saves machine time) likely weakening guarantees

Related answers:

uvsmtid
  • 3,771
  • 3
  • 33
  • 55