Как обеспечить использование конструктора перемещения
Код ниже дает ошибку:
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;
};