Когда действительно добавятся конструктор перемещения и оператор присваивания перемещения? - PullRequest
4 голосов
/ 18 января 2011

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

class semi_complex
{
    std::vector<std::string> strings_;

public:

    semi_complex(semi_complex&& other);
    semi_complex& operator=(semi_complex&& other);
    ...
};

Итак, при каком количестве и каких типах переменных-членов имеет смысл добавлять конструкторы перемещения и операторы присваивания перемещения?

Ответы [ 5 ]

8 голосов
/ 18 января 2011

Это уже имеет смысл по чисто семантическим причинам, даже если вы полностью исключаете аспекты оптимизации.Просто представьте себе случай, когда класс не / не может реализовать копирование.Например, boost::scoped_ptr нельзя скопировать, но его можно переместить!

6 голосов
/ 23 января 2011

В дополнение к уже полученным отличным ответам я хотел бы добавить несколько перспективных деталей:

В последней версии C ++ 0x появились новые правила для автоматической генерации конструктора перемещения и оператора назначения перемещения. Хотя эта идея не является совершенно новой, последние правила находятся в черновике только с октября 2010 года и пока еще не широко доступны в компиляторах.

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

Вы также можете явно задавать по умолчанию членов вашего движения:

semi_complex(semi_complex&&) = default;
semi_complex& operator=(semi_complex&&) = default;

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

В тесно связанном последнем изменении: если в вашем классе есть явный деструктор и неявные члены-копии, неявное создание этих членов теперь не рекомендуется (комитет хотел бы удалить неявное создание-копию, когда есть явный деструктор, но не может из-за обратной совместимости).

Итак, в итоге, всякий раз, когда вы объявляете деструктор, вам, вероятно, следует подумать о явном объявлении копируемых и перемещаемых членов.

4 голосов
/ 18 января 2011

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

4 голосов
/ 18 января 2011

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

Следовательно, семантика перемещения имеет смысл, когда

  • включает динамическое выделение памяти
  • перемещение имеет смысл для одной или нескольких переменных-членов (что означает, что они включают где-то динамическое распределение)вдоль линии).
1 голос
/ 18 января 2011

Независимо от всего, что может быть автоматически выполнено компилятором, я бы сказал, что:

  • Если у какого-либо члена есть значимая и полезная семантика перемещения, у класса также должна быть эта семантика перемещения.(-> std::vector члены)
  • Если при копировании используются динамические выделения, операции перемещения имеют смысл.

Иначе, если перемещение может сделать что-то более эффективное, чем копирование,имеет смысл добавить это.В вашем really_trivial движение может быть таким же эффективным, как и копия.

...