Thinking about this topic I got a thought (given that I'm talking about C++11
) that a user-defined swap
should be provided only for types which don't provide a move semantic
, more precisely a move assignment
operator ('cause I think it's more common to have a move ctr
while lack a move assignment
operator); or the move ctor
and/or the move assignment
operator have some side-effects which ain't desired to happen.
Let's see the examples: [ the same as in a linked topic ]
class remote_connection
{
public:
int socket_fd;
friend void swap( remote_connection& lhs, remote_connection& rhs ) = delete;
}
As we have NO provided a user-defined swap
the code trying to swap objects of a remote_connection
type calls a swap
instantiated from std::swap
which causes a move construction and two move assignments to happen (as @1201ProgramAlarm indicated).
So, to swap objects a compiler issues: one function call to a std::swap
, one call to a move ctr
and two calls to a move assign
operator. Which leads to 3 int
copies to make an actual swap.
As a result: 4 function calls and 3 copies.
Let's implement a swap
method:
class remote_connection
{
public:
int socket_fd;
friend void swap( remote_connection& lhs, remote_connection& rhs )
{
using std::swap;
swap( lhs.socket_fd, rhs.socket_fd );
}
}
As we have provided a user-defined swap
the code trying to swap objects of a remote_connection
type calls this user-defined swap
which causes 3 copies for int
to happen (create a tmp from a rhs, copy a lhs to the rhs, copy the tmp to the lhs).
So, to swap objects a compiler issues: one function call to a swap
(found by ADL), one call to a std::swap(int&, int&)
. Which also leads to 3 int
copies to make an actual swap.
As a result: 2 function calls and 3 copies.
The user-defined swap won, but what if we add some members to our class:
class remote_connection
{
public:
int socket_fd;
int a, b, c, d, e;
friend void swap( remote_connection& lhs, remote_connection& rhs )
{
using std::swap;
swap( lhs.socket_fd, rhs.socket_fd );
swap( lhs.a, rhs.a );
swap( lhs.b, rhs.b );
swap( lhs.c, rhs.c );
swap( lhs.d, rhs.d );
swap( lhs.e, rhs.e );
}
}
Here we have: 8 function calls and 6 copies. But if we didn't provide the user-defined swap
, we'd have: 4 function calls and 6 copies.
So, it seems that whatever class we have (derived from a class with plenty members, consisting of plenty sub-objects of built-in and user-defined types) it's more sane, IMHO, to not provide a user-defined swap
. Not only this, but also such the swap
is hard to support (if we changed something in a class and forgot to reflect that changes in the swap
we get a surprise.)
So the questions is: "If we have no side-effects in move ctr
/move assign operator
and provide them both, do we have to implement a user-defined swap
, or is it a good practice to rely on stl
provided one in such circumstances?"
Sorry for such ammount of so, I'm not a native speaker :)
P.S. I forgot to add that we need, IMHO, a user-defined swap
if we're going to implement a copy-and-swap
idiom and we've implemented a move assignment
operator.
Aucun commentaire:
Enregistrer un commentaire