Ответ 1
Правильный общий способ состоит в том, чтобы перемещать-конструировать каждый элемент, но то, что в любом случае имеет версия с испражнением:
T(T && rhs)
: a(std::move(rhs.a))
, b(std::move(rhs.b))
{ }
В качестве грубого правила вы должны использовать определение по умолчанию, если это все, что вам нужно, и вы должны написать ex & shy; pli & shy; cit move constructor, если вы делаете что-то, что ex & shy; pli & shy; citly реализует семантику перемещения, такую как диспетчер ресурсов уникальной собственности:
URM(URM && rhs)
: resource(rhs.resource)
{
rhs.resource = nullptr;
}
Показателем того, подходит ли это, вероятно, является ли ваш класс определяемым пользователем de & shy; struc & shy; tor. В этом примере деструктор освободит управляемый ресурс, и это должно произойти только один раз, поэтому объект с переместившимся объектом должен быть изменен.
Это не связано, но поскольку вы упоминаете оператор присваивания, здесь используется популярная именованная подкачка и назначение/своп:
void swap(URM & rhs) noexcept // assume members are noexcept-swappable!
{
using std::swap;
swap(resource, rhs.resource);
// ...
}
URM & operator=(URM rhs) noexcept // pass by value
{
rhs.swap(*this);
return *this;
}
Красота этого подхода заключается в том, что вам нужна только одна версия оператора присваивания, которая работает как со временными, так и с не временными, используя при необходимости конструкцию перемещения, и пока все ваши члены хорошо разработаны, вы также нужна только одна функция swap
. Кроме того, если функция подкачки не выбрасывает (которую должен разрешить хорошо продуманный класс), то ваш оператор присваивания не бросает, так как все возможные исключения будут уже встречаться на сайте вызова.