Как обеспечить использование конструктора перемещения

Код ниже дает ошибку:

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

теперь я знаю, что это происходит потому, что конструктор копирования (намеренно) неявно удаляется путем указания конструктора перемещения, а копирование вектора вызывает вызовы (удаленного) конструктора копирования. Думаю, я также понимаю, почему используются конструктор копирования и оператор присваивания вектора. Я явно хочу использовать конструктор перемещения и оператор присваивания: переместить объект, а также переместить вектор, который он содержит. Итак, как мне заставить мой конструктор перемещения / оператор присваивания использовать векторный конструктор перемещения / оператор присваивания?

Вот код:

#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;
    };
};

3 ответа

Решение

Чтобы гарантировать, что конструктор "move" и операторы присваивания вызываются, вам нужно предоставить объект правильной категории значений. Категория значений используется, чтобы определить, какие операторы и конструкторы могут быть использованы.

использование std::move изменить категорию значения (в данном случае от lvalue) на xvalue (значение r, которое можно переместить из).

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

move не копирует и не изменяет объект каким-либо образом, это просто приведение к rvalue-ссылке типа аргумента - следовательно, изменение категории значения.

Просто позвони std::move по векторам в выражении, в которое вы хотите перейти от них:

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;
    };
};

Даже если вы берете в Rvalue ссылки, rhs а также orig все еще являются lvalues ​​в функции, поэтому вам нужно вызвать std::move на них.

Если все члены вашего класса являются объектами классов с правильно определенным конструктором перемещения / оператором присваивания, вам лучше использовать конструктор перемещения / оператор присваивания по умолчанию для вашего класса. Это было бы намного проще и менее подвержено ошибкам и обеспечило бы вызов конструктора перемещения / оператора присваивания членов класса.

В вашем конкретном примере это будет:

class A
{
private:
    vector<B> vec;
public:
    A() : vec() {};
    A(A&&) = default;
    A& operator=(A&&) = default;
};
Другие вопросы по тегам