简体   繁体   中英

C++: assignment operator: pass-by-value (copy-and-swap) vs pass-by-reference

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?

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.

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.

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:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM