Не могли бы вы привести конкретный пример, где это было бы полезно. Например, насколько я понимаю, назначение перемещения в общем случае может быть реализовано как
this->swap(rhv);
Метод обмена, вероятно, полезен в любом случае, если класс извлекает выгоду из семантики перемещения. Это прекрасно делегирует работу по освобождению старых ресурсов *this
обычному деструктору.
Без конкретных примеров, показывающих, что новый тип деструктора является элегантным способом получения правильного кода, ваше предложение выглядит не очень привлекательно.
Также, в соответствии с последними ревизиями, конструктор перемещения / оператор присваивания может быть установлен по умолчанию. Это означает, что очень вероятно
мои занятия будут выглядеть так:
class X
{
well_behaved_raii_objects;
public:
X(X&& ) = default;
X& operator=(X&&) = default;
};
Никакого деструктора! Что могло бы заставить меня иметь в своем распоряжении два деструктора?
Также учтите, что у оператора присваивания есть старые ресурсы для работы. В соответствии с текущим стандартом, вы должны быть осторожны, что нормальный вызов деструктора в порядке как после конструирования и назначения, так и IMO, так же как и с предложенным деструктором перемещения, вы должны позаботиться в конструкторе и операторе присваивания, что один и тот же деструктор перемещения может быть безопасно позвонил. Или вы хотели бы два деструктора движения - по одному для каждого? :)
Переработанный пример msdn в комментариях с конструктором перемещения / назначением
#include <algorithm>
class MemoryBlock
{
public:
// Simple constructor that initializes the resource.
explicit MemoryBlock(size_t length)
: length(length)
, data(new int[length])
{
}
// Destructor.
~MemoryBlock()
{
delete[] data; //checking for NULL is NOT necessary
}
// Copy constructor.
MemoryBlock(const MemoryBlock& other)
: length(other.length)
, data(new int[other.length])
{
std::copy(other.data, other.data + length, data);
}
// Copy assignment operator (replaced with copy and swap idiom)
MemoryBlock& operator=(MemoryBlock other) //1. copy resource
{
swap(other); //2. swap internals with the copy
return *this; //3. the copy's destructor releases our old resources
}
//Move constructor
//NB! C++0x also allows delegating constructors
//alternative implementation:
//delegate initialization to default constructor (if we had one), then swap with argument
MemoryBlock(MemoryBlock&& other)
: length(other.length)
, data(other.data)
{
other.data = 0; //now other can be safely destroyed
other.length = 0; //not really necessary, but let's be nice
}
MemoryBlock& operator=(MemoryBlock&& rhv)
{
swap(rhv);
//rhv now contains previous contents of *this, but we don't care:
//move assignment is supposed to "ruin" the right hand value anyway
//it doesn't matter how it is "ruined", as long as it is in a valid state
//not sure if self-assignment can happen here: if it turns out to be possible
//a check might be necessary, or a different idiom (move-and-swap?!)
return *this;
}
// Retrieves the length of the data resource.
size_t Length() const
{
return length;
}
//added swap method (used for assignment, but recommended for such classes anyway)
void swap(MemoryBlock& other) throw () //swapping a pointer and an int doesn't fail
{
std::swap(data, other.data);
std::swap(length, other.length);
}
private:
size_t length; // The length of the resource.
int* data; // The resource.
};
Некоторые комментарии к исходному образцу MSDN:
1) проверка на NULL до delete
не нужна (возможно, это сделано для вывода, который я удалил, возможно, это указывает на недопонимание)
2) удаление ресурсов в операторе присваивания: дублирование кода. С идиомой копирования и замены удаление ранее удержанных ресурсов делегируется деструктору.
3) идиома копирования и обмена также делает ненужными проверки самоназначения. Это не проблема, если ресурс копируется до , он удаляется. - («Копировать ресурс независимо», с другой стороны, причиняет боль только тогда, когда вы ожидаете много самостоятельных заданий, выполненных с этим классом.)
4) В операторе присваивания в примере MSDN отсутствует какой-либо тип безопасности исключений: если при выделении нового хранилища происходит сбой, класс остается в недопустимом состоянии с недопустимым указателем. После уничтожения произойдет неопределенное поведение.
Это можно улучшить, аккуратно переупорядочив операторы и установив удаленный указатель на NULL между ними (к сожалению, кажется, что инвариант этого конкретного класса заключается в том, что он всегда содержит ресурс, поэтому его чистая потеря случай исключения тоже не идеален). В отличие от этого, при копировании и замене, если происходит исключение, левое значение остается в исходном состоянии (гораздо лучше, операция не может быть завершена, но потеря данных можно избежать).
5) Проверка самопредставления выглядит особенно сомнительной в операторе присваивания. Я не вижу, как значение левой руки может быть таким же, как значение правой руки в первую очередь. Потребуется ли a = std::move(a);
, чтобы достичь идентичности (похоже, это будет неопределенное поведение в любом случае?)?
6) Опять же, назначение перемещения - это ненужное управление ресурсами, которое моя версия просто делегирует обычному деструктору.
Вывод: дублирование кода, которое вы видите, можно избежать, оно вводится только наивной реализацией (которую вы по какой-то причине склонны видеть в руководствах, вероятно, потому, что код с дублированием проще для учеников).
Чтобы предотвратить утечку ресурсов, всегда бесплатно
ресурсы (такие как память, файл
ручки и розетки) в движении
оператор присваивания.
... если редукция кода вас устраивает, в противном случае используйте деструктор повторно.
Для предотвращения невосстановимого
уничтожение ресурсов, правильно
справиться с самопредставлением в движении
оператор присваивания.
... или убедитесь, что вы никогда не удаляете что-либо, прежде чем сможете его заменить.
Или, скорее, вопрос SO: возможно ли самоопределение в случае назначения перемещения в четко определенной программе.
Кроме того, из моего черновика (3092) я обнаружил, что если в классе нет определенного пользователем конструктора / оператора копирования, и ничто не мешает существованию конструктора / назначения перемещения, то один будет неявно объявлен как дефолтный . Если я не ошибаюсь, это означает: если членами являются такие вещи, как строки, вектор, shared_ptrs и т. Д., И в этом случае вы обычно не пишете конструктор / назначение копирования, вы получите конструктор перемещения / назначение перемещения бесплатно .