Pregunta Cómo asegurarse de que se usa el constructor de movimientos


El siguiente código da el error:

use of deleted function ‘constexpr B::B(const B&)’

ahora, sé que esto sucede porque el constructor de copia se elimina (intencionalmente) de manera implícita al especificar un constructor de movimiento, y que al copiar el vector se generan las llamadas al constructor de copia (eliminado). Creo que también entiendo por qué se utilizan el constructor de copia del vector y el operador de asignación. Claramente, quiero usar el constructor de movimientos y el operador de asignación: mueve el objeto, así que también mueve el vector que contiene. Asi que, ¿Cómo puedo hacer que mi constructor / operador de asignación de movimiento use el operador de asignación / asignación de movimiento del vector?

Aquí está el código:

#include <vector>

class B {
private:
    /* something I don't want to copy */
public:
    B() {};
    B(B&& orig) {/* move contents */};
    B& operator=(B&& rhs) {
        /* move contents */
        return *this;
    };
};

class A {
private:
    vector<B> vec;
public:
    A() : vec() {};
    A(A&& orig) : vec(orig.vec) {};
    A& operator=(A&& rhs) {
        vec = rhs.vec;
        return *this;
    };
};

5
2018-02-12 09:21


origen


Respuestas:


Para asegurarse de que el constructor "mover" y los operadores de asignación sean llamados, usted necesita proporcionar un objeto de la categoría de valor correcta. La categoría de valor se usa para determinar qué operadores y constructores podrían usarse.

Utilizar std::move para cambiar el categoría de valor (desde el valor l en este caso) a un valor x (un valor r, que se puede mover desde).

// ...
A(A&& orig) : vec(std::move(orig.vec)) {};
A& operator=(A&& rhs) {
    vec = std::move(rhs.vec);
    return *this;
};

los move no copia ni cambia el objeto de ninguna manera, simplemente es un molde para una referencia de valor real del tipo de argumento, y por lo tanto modifica la categoría de valor.


5
2018-02-12 09:32



Solo llama std::move en los vectores en la expresión en la que quieres moverte de ellos:

class A {
private:
    vector<B> vec;
public:
    A() : vec() {};
    A(A&& orig) : vec(std::move(orig.vec)) {};
    //                ^^^^^^^^^
    A& operator=(A&& rhs) {
        vec = std::move(rhs.vec);
        //    ^^^^^^^^^
        return *this;
    };
};

A pesar de que toma en referencias de valor, rhs y orig Todavía hay valores en la función, por lo que debe llamar std::move en ellos.


9
2018-02-12 09:25



Si todos los miembros de su clase son objetos de clases con un constructor / operador de asignación de movimiento correctamente definido, debería utilizar mejor defecto mover constructor / operador de asignación para su clase. Esto sería mucho más fácil y menos propenso a errores y garantizaría la llamada del operador de asignación / asignación de movimiento de los miembros de la clase.

En tu ejemplo particular sería:

class A
{
private:
    vector<B> vec;
public:
    A() : vec() {};
    A(A&&) = default;
    A& operator=(A&&) = default;
};

2
2018-02-12 10:31