c++ - español - ¿Se está desaprobando el uso de std:: swap ahora que tenemos semántica de movimiento?
swap c++ español (4)
¿Se está desaprobando el uso de
std::swap
ahora que tenemos semántica de movimiento?
No. Esta es la versión genérica, pero puede optimizarla para omitir una operación de tercer movimiento. Mi preferencia es combinar el modismo copiar y cambiar con la personalización de std::swap
para mis clases.
Eso significa que tendré:
class Aaaa
{
public:
Aaaa(); // not interesting; defined elsewhere
Aaaa(Aaaa&& rvalueRef); // same
Aaaa(const Aaaa& ref); // same
~Aaaa(); // same
Aaaa& operator=(Aaaa object) // copy&swap
{
swap(object);
return *this;
}
void swap(Aaaa& other)
{
std::swap(dataMember1, other.dataMember1);
std::swap(dataMember2, other.dataMember2);
// ...
}
// ...
};
namespace std
{
template<> inline void std::swap(Aaaa& left, Aaaa& right)
{ left.swap(right); }
}
Posible duplicado:
Mover la semántica == función de intercambio personalizado obsoleto?
Así es como se ve std::swap
en C ++ 11:
template<typename T>
void swap(T& x, T& y)
{
T z = std::move(x);
x = std::move(y);
y = std::move(z);
}
¿Todavía tengo que especializar std::swap
para mis propios tipos, o std::swap
será lo más eficiente posible, siempre que mi clase defina un constructor de movimiento y un operador de asignación de movimiento, por supuesto?
Eso dependerá de tus Tipos.
Lo moverá de xa z, de y a x, de z a y. Eso es tres operaciones de copia de la representación subyacente (tal vez solo un puntero, tal vez algo más, quién sabe)
Ahora quizás puedas crear un intercambio más rápido para tu tipo (xor swap truick, inline assembler, o tal vez std :: swap para tus tipos subyacentes sea más rápido).
O tal vez también su compilador optimiza y básicamente optimiza ambos casos en las mismas instrucciones (como tener el temporal en un registro).
Yo personalmente tiendo a implementar siempre una función de miembro de intercambio que se llamará desde varios lugares, incluyendo cosas como la asignación de movimiento, pero YMMV.
Este swap()
llama a un constructor de movimiento y 2 asignaciones de movimiento. Creo que uno puede escribir swap()
más eficiente para su tipo particular de clase como,
class X
{
int * ptr_to_huge_array;
public:
// ctors, assgn ops. etc. etc.
friend void swap(X& a, X& b)
{
using std::swap;
swap(a.ptr_to_huge_array, b.ptr_to_huge_array);
}
};
independientemente de la implementación del constructor de movimientos y el operador de asignación.
La especialización de std::swap
ahora es opcional, pero no desaprobada. La razón es el rendimiento.
Para el código de creación de prototipos, y quizás incluso para muchos códigos de envío, std::swap
será bastante rápido. Sin embargo, si se encuentra en una situación en la que necesita buscar cada bit de su código, escribir un intercambio personalizado puede ser una gran ventaja de rendimiento.
Considere el caso en el que su clase tiene esencialmente un puntero propietario y el constructor de movimiento y la asignación de movimiento solo tienen que lidiar con ese puntero. Contar las cargas y las tiendas de la máquina para cada miembro:
Mover constructor: 1 carga y 2 tiendas.
Asignación de movimiento: 2 cargas y 2 tiendas.
Cambio personalizado: 2 cargas y 2 tiendas.
std::swap
es 1 movimiento de construcción y 2 asignaciones de movimiento, o: 5 cargas y 6 tiendas.
Un intercambio personalizado es potencialmente aún dos o tres veces más rápido que std::swap
. Aunque cada vez que intentas averiguar la velocidad de algo contando cargas y tiendas, ambos van a ser perversos rápidamente.
Nota: Al calcular el costo de su asignación de movimiento, asegúrese y tenga en cuenta que se moverá a un valor movido (en el algoritmo std::swap
). Esto a menudo niega el costo de una desasignación, aunque a costa de una sucursal.