Что-то беспокоит меня:
MyClass& operator=(const MyClass& other)
{
MyClass tmp(other);
swap(tmp);
return *this;
}
Во-первых, чтение слова «своп», когда мой ум думает «копировать», раздражает мой здравый смысл. Кроме того, я подвергаю сомнению цель этой причудливой уловки. Да, любые исключения при построении новых (скопированных) ресурсов должны происходить до перестановки, что кажется безопасным способом убедиться, что все новые данные заполнены, прежде чем они будут запущены.
Отлично. Итак, что насчет исключений, которые происходят после обмена? (когда старые ресурсы уничтожаются, когда временный объект выходит из области видимости) С точки зрения пользователя назначения операция завершилась неудачно, за исключением того, что это не так. У него огромный побочный эффект: копирование действительно произошло. Это была только некоторая очистка ресурса, которая потерпела неудачу. Состояние целевого объекта было изменено, несмотря на то, что внешняя операция кажется неудачной.
Итак, я предлагаю вместо «своп» сделать более естественный «перевод»:
MyClass& operator=(const MyClass& other)
{
MyClass tmp(other);
transfer(tmp);
return *this;
}
Все еще создается временный объект, но следующее немедленное действие - освободить все текущие ресурсы места назначения перед перемещением (и NULLing, чтобы они не были освобождены дважды) ресурсов источника к нему.
Вместо {конструировать, двигать, разрушать} я предлагаю {конструировать, разрушать, перемещать}. Ход, который является самым опасным действием, является последним, предпринятым после того, как все остальное было улажено.
Да, сбой уничтожения является проблемой в любой схеме. Данные либо повреждены (скопированы, если вы об этом не думали), либо потеряны (освобождены, если вы об этом не думали). Потерянный лучше, чем испорченный. Нет данных лучше плохих.
Перевод вместо обмена. В любом случае, это мое предложение.