Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should copy assignment operator leverage std::swap as a general rule?

Tags:

c++

c++11

Is it a good general practice to always implement my copy assignment operators using std::swap? My understanding is that this provides a way to share the copy constructor implementation. I'd like to avoid duplicating the actual copy logic itself. So here is what I'd do:

class Foo
{
public:
    Foo(Foo const& other) { /* assume valid implementation */ }

    Foo& operator= (Foo other)
    {
        std::swap(*this, other);
        return *this;
    }
};

The act of passing "other" into the assignment operator performs copy construction (we've shared the copy logic at this point). I assume the swap will invoke move construction (which has a compiler-generated implementation here).

I've been doing this to pretty much every class I implement copy construction for, since the assignment & constructor never have different implementations.

like image 886
void.pointer Avatar asked Sep 19 '14 20:09

void.pointer


2 Answers

Your code does not have a move constructor. Your copy constructor blocks the automatic creation of a move constructor, and attempting to move your class instead copies it.

For move-assign, your operator= also blocks its automatic implementation, and can be used in its place.

The end result is an infinite recursive call of = (live code).

If you follow the rule of 0, you need neither a copy constructor, move constructor, move-assignment, copy-assignment, or destructor. If you write any of them, you should be prepared to write all of them.

Using std::swap can be useful, but because you have to write your move-assign and move-construct, doing either in terms of std::swap is an infinite recursion waiting to happen.

like image 116
Yakk - Adam Nevraumont Avatar answered Nov 22 '22 22:11

Yakk - Adam Nevraumont


If Foo contains non-static data members std::vector or std::string, or contains data members that contain vector or string (i.e. even indirectly), then this can be a very effective way to slow your code down. It can even be more effective than calling std::sleep_for as the latter doesn't waste battery power on mobile devices.

The reason is that a copy assignment which calls the vector or string copy assignment has the chance to reuse the container's capacity. Whereas the swap idiom always throws away capacity.

For more info, see my ACCU 2014 talk, slides 43-53.

In particular, note this performance chart which shows the speed increase of calling vector's copy assignment operator vs doing the copy/swap idiom with a vector data member.

this http://howardhinnant.github.io/accu_2014_48.pdf

At best, the copy/swap idiom is as fast as using vector's copy assignment (when capacity is never sufficient). At worst (when capacity is always sufficient), copy/swap is nearly 8X slower. On average, copy/swap entails a 70% speed hit (for this test).

like image 34
Howard Hinnant Avatar answered Nov 22 '22 22:11

Howard Hinnant