¿El lenguaje de copia e intercambio sigue siendo útil en C ++ 11?
Me refiero a esta pregunta:¿Qué es el lenguaje de copia e intercambio?
Efectivamente, la respuesta anterior conduce a la siguiente implementación:
class MyClass
{
public:
friend void swap(MyClass & lhs, MyClass & rhs) noexcept;
MyClass() { /* to implement */ };
virtual ~MyClass() { /* to implement */ };
MyClass(const MyClass & rhs) { /* to implement */ }
MyClass(MyClass && rhs) : MyClass() { swap(*this, rhs); }
MyClass & operator=(MyClass rhs) { swap(*this, rhs); return *this; }
};
void swap( MyClass & lhs, MyClass & rhs )
{
using std::swap;
/* to implement */
//swap(rhs.x, lhs.x);
}
Sin embargo, observe que podríamos evitar el swap () por completo, haciendo lo siguiente:
class MyClass
{
public:
MyClass() { /* to implement */ };
virtual ~MyClass() { /* to implement */ };
MyClass(const MyClass & rhs) { /* to implement */ }
MyClass(MyClass && rhs) : MyClass() { *this = std::forward<MyClass>(rhs); }
MyClass & operator=(MyClass rhs)
{
/* put swap code here */
using std::swap;
/* to implement */
//swap(rhs.x, lhs.x);
// :::
return *this;
}
};
Tenga en cuenta que esto significa que ya no tendremos una búsqueda válida dependiente del argumento en std :: swap con MyClass.
En resumen, hay alguna ventaja de tener el método swap ().
editar:
Me di cuenta de que hay un error terrible en la segunda implementación anterior, y es algo muy grande, así que lo dejaré como está para instruir a cualquiera que se encuentre con esto.
si operador = se define como
MyClass2 & operator=(MyClass2 rhs)
Entonces, cuando rhs sea un valor r, se llamará al constructor de movimientos. Sin embargo, esto significa que al usar:
MyClass2(MyClass2 && rhs)
{
//*this = std::move(rhs);
}
Observe que termina con una llamada recursiva al constructor de movimientos, ya que operator = llama al constructor de movimientos ...
Esto es muy sutil y difícil de detectar hasta que se obtiene un desbordamiento de la pila en tiempo de ejecución.
Ahora la solución a eso sería tener ambos
MyClass2 & operator=(const MyClass2 &rhs)
MyClass2 & operator=(MyClass2 && rhs)
Esto nos permite definir los constructores de copia como
MyClass2(const MyClass2 & rhs)
{
operator=( rhs );
}
MyClass2(MyClass2 && rhs)
{
operator=( std::move(rhs) );
}
Observe que escribe la misma cantidad de código, los constructores de copia vienen "de forma gratuita" y simplemente escriben operator = (&) en lugar del constructor de copia y operator = (&&) en lugar del método swap ().