español c++ templates c++11 swap move-semantics

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.