¿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 ().

Respuestas a la pregunta(4)

Su respuesta a la pregunta