std::swap
is implemented by performing move construction followed by two move assignment operations. So unless you implement your own swap
operation that replaces the standard-provided one, your code as presented is an infinite loop.
So you can either implement 2 operator=
methods, or implement one operator=
method and one swap
method. In terms of the number of functions called, it's ultimately identical.
Furthermore, your version of operator=
is sometimes less efficient. Unless the construction of the parameter is elided, that construction will be done via a copy/move from the caller's value. Following this are 1 move construction and 2 move assignments (or whatever your swap
does). Whereas proper operator=
overloads can work directly with the reference it is given.
And this assumes that you cannot write an optimal version of actual assignment. Consider copy-assigning one vector
to another. If the destination vector
has enough storage to hold the size of the source vector... you don't need to allocate. Whereas if you copy construct, you must allocate storage. Only to then free the storage you could have used.
Even in the best case scenario, your copy/move&swap will be no more efficient than using a value. After all, you're going to take a reference to the parameter; std::swap
doesn't work on values. So whatever efficiency you think will be lost by using references will be lost either way.
The principle arguments in favor of copy/move&swap are:
Reducing code duplication. This is only advantageous if your implementation of copy/move assignment operations would be more or less identical to the copy/move construction. This is not true of many types; as previously stated, vector
can optimize itself quite a bit by using existing storage where possible. Indeed many containers can (particularly sequence containers).
Providing the strong exception guarantee with minimal effort. Assuming your move constructor is noexcept.
Personally, I prefer to avoid the scenario altogether. I prefer letting the compiler generate all of my special member functions. And if a type absolutely needs me to write those special member functions, then this type will be as minimal as possible. That is, it's sole purpose will be managing whatever it is that requires this operation.
That way, I just don't have to worry about it. The lion's share of my classes don't need any of these functions to be explicitly defined.
v
into*this
, but swap with it. Please see the updated question. – Bolesoperator=
can be markednoexcept
, since it doesn't throw in the function body. Should throwing in parameter construction be considered? – Boles