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.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With