Когда неявные конструкторы перемещения недостаточно хороши?

Когда неявные конструкторы перемещения недостаточно хороши?

Должен ли я относиться к нему как к деструкторам и конструкторам копирования, где это обычно необходимо только в том случае, если я управляю своей собственной памятью?

Достаточно ли хорош неявный конструктор перемещения в этом (очень надуманном) сценарии:

class A
{
private:
    B b;
    std::string name;

public:
    A();
    std::string getName() const {
        return name;
    }

    B getB() const {
        return b;
    }
};

class B
{
private:
    std::vector list;

public: 
    B();
    std::vector getList() const {
        return list;
    }
};

person DormoTheNord    schedule 13.06.2013    source источник
comment
Иногда вам нужно вручную написать конструктор перемещения, чтобы элементы были выровнены друг с другом. Если у вас есть элемент строки и элемент int, который ссылается на определенную часть строки, то при перемещении объекта член int, вероятно, должен быть сброшен на 0.   -  person Mooing Duck    schedule 14.06.2013
comment
Неявный конструктор перемещения объекта типа A вызовет конструктор перемещения name и b (который также является неявным и вызывает конструктор перемещения list). Все двигалось нормально, тебе делать нечего. Напишите свой собственный, если A имеет собственное управление кучей или неперемещаемые элементы (в этом случае вы, вероятно, захотите обрабатывать эти объекты-члены отдельно).   -  person Pixelchemist    schedule 14.06.2013
comment
Когда неявные конструкторы перемещения недостаточно хороши? — Когда они даже не созданы из-за глупости крупного поставщика компилятора. ;) (Извините за разглагольствования, но это определенно самая отсутствующая функция в VC++.)   -  person Christian Rau    schedule 14.06.2013


Ответы (2)


Ответ здесь основан на результатах поиска Google.

Цитата из блога Andrzej C++

> Когда я должен определить конструктор перемещения для моего класса?

Это сильно зависит от того, что делает ваш класс и как он реализован. Во-первых, для «агрегированных» классов, которые только группируют другие данные для удобства/ясности, конструкторы перемещения будут неявно генерироваться компилятором. Рассмотрим следующий класс.

struct Country {
  std::string name;
  std::vector<std::string>  cities;
};

В типичной структуре C++ многие специальные функции-члены, такие как конструктор копирования, присваивание копии, деструктор, генерируются автоматически. Это также включает в себя конструктор перемещения (и назначение перемещения).

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

  1. Сделать два одинаковых объекта из одного — это должно быть дорого.
  2. Перемещение одного объекта из одного места памяти в другое — это можно сделать очень быстро.

Если для вашего класса можно реализовать конструктор перемещения, который будет быстрее, чем конструктор копирования, вам следует реализовать его в целях оптимизации скорости выполнения. Мы видели, как его можно реализовать для вектора в эта ссылка. Однако не для всех типов может быть реализован такой конструктор перемещения, более быстрый, чем конструктор копирования. Рассмотрим следующее матричное представление.

class Matrix {
  std::complex<long double> data[1000][1000];
};

Поскольку вся память, необходимая для матричного представления, объявлена ​​в области класса (в отличие от вектора, в котором используется память, распределенная в куче), нет возможности применить только небольшое количество назначений. Нам нужно будет сделать копирование для каждого элемента массива. Нет смысла определять конструктор перемещения, так как это будет не быстрее, чем копирование.

Еще одна веская причина для предоставления конструктора перемещения, если вы хотите, чтобы ваш тип, который нельзя копировать (поскольку он похож на RAII и представляет ресурс), по-прежнему передавался по значению, когда копирование не требуется, и сохранялся в Контейнеры STL. Такая уникальная семантика владения более подробно объясняется в эта ссылка.

person taocp    schedule 13.06.2013
comment
Спасибо, именно тот ответ, который я искал. - person DormoTheNord; 14.06.2013
comment
@DormoTheNord Добро пожаловать. Надо отдать должное Анджею. Я тоже узнал из вашего вопроса. - person taocp; 14.06.2013

Обязательный ответ на правило нуля: создавайте либо классы, управляющие одним ресурсом, либо таким образом переопределяют перемещение/копирование/деструктор/назначение - или классы, которые объединяют менеджеров ресурсов и не нуждаются в переопределениях.

person Casey    schedule 14.06.2013