Почему использование варианта перемещения std :: vector :: push_back вызывает конструктор копирования перемещенного элемента? - PullRequest
0 голосов
/ 20 сентября 2018

Вот некоторый код, который не скомпилируется, потому что push_back пытается вызвать конструктор копирования в MoveOnlyClass, который удален:

class MoveOnlyClass
{
public:
    MoveOnlyClass() {};
    MoveOnlyClass& operator=(const MoveOnlyClass& other) = delete;
    MoveOnlyClass(const MoveOnlyClass& other) = delete;
};

int main()
{
    std::vector<MoveOnlyClass> vec;
    vec.push_back(std::move(MoveOnlyClass()));
}

Почему это происходит?Конечно, вектор должен вызывать только конструктор перемещения.Как правильно переместить объект в вектор?

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Ответ @Xirema закрывает вопрос о проблеме в коде и объясняет, почему это так.

Я просто хочу подкрепить его соответствующими выдержками из спецификации языка, чтобы сделатьвещи официальные.Таким образом, из [class.copy.ctor¶8] :

(8) Если определение класса X не объявляет явно конструктор перемещения, не явныйбудет неявно объявлено как значение по умолчанию тогда и только тогда, когда

  • (8.1) X не имеет объявленного пользователем конструктора копирования ,

Для этого следует добавить, что объявление как удаленное все еще объявляется.Следовательно, в соответствии с этим мы не получаем неявно объявленный конструктор перемещения в вашем случае, так как у нас уже есть объявленный пользователем конструктор копирования .

Далее, в разделе [dcl.fct.def.delete¶3] :

Можно сделать класс не копируемым, т.е. только для перемещения, используя удаленные определенияконструктора копирования и оператора назначения копирования, , а затем предоставление по умолчанию определений конструктора перемещения и оператора назначения перемещения.

0 голосов
/ 20 сентября 2018

Удаление конструктора копирования / функции назначения копирования также неявно удаляет функцию перемещения-конструктора / назначения перемещения.Если вы намереваетесь сделать объект подвижным, но не копируемым, вам также необходимо default конструктор перемещения.

class MoveOnlyClass
{
public:
    MoveOnlyClass() {};
    MoveOnlyClass& operator=(const MoveOnlyClass& other) = delete;
    MoveOnlyClass(const MoveOnlyClass& other) = delete;
    MoveOnlyClass& operator=(MoveOnlyClass&& other) = default;
    MoveOnlyClass(MoveOnlyClass&& other) = default;
};

//Will now compile as you expect
int main()
{
    std::vector<MoveOnlyClass> vec;
    vec.push_back(std::move(MoveOnlyClass()));
}

Кроме того, std::move(T()) является избыточным;создание такого объекта на месте уже сделает его R-значением, а использование std::move, когда вам не нужно, может предотвратить некоторые виды оптимизации компилятора (например, Copy Ellision).

...