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

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

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

6

Решение

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

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

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

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

5

Другие решения

Просто позвони 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 на них.

9

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

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

class A
{
private:
vector<B> vec;
public:
A() : vec() {};
A(A&&) = default;
A& operator=(A&&) = default;
};
2
По вопросам рекламы [email protected]