Идиома copy-and-swap — это идиома языка программирования C++, позволяющая разрабатывать устойчивые к исключениям операторы присваивания.
Идиома базируется на идиоме «Получение ресурса есть инициализация».
Идиома предполагает реализацию следующих функций-членов класса: конструктора копирования; оператора присваивания; метода swap, не генерирующего исключения и принимающего ссылку на объект класса.
Пример:
class Copyable { public: Copyable& operator=(const Copyable &_v) { Copyable tmp(_v); this->swap(tmp); return *this;
void swap(Copyable &_v) noexcept;
Устойчивость к исключениям заключается в том, что в операторе присваивания Copyable& operator=(const Copyable &) нет точки, где генерация исключения могла бы привести к утечке памяти.
Оператор присваивания сначала пытается захватить ресурс «временная копия присваиваемого объекта» (tmp) и в случае успеха меняет его содержимое с содержимым текущего объекта (this). Поскольку метод swap объявлен как не генерирующий исключения (noexcept), единственной точкой, где может возникнуть исключение, является копирование объекта _v. Если копирование не удается, то управление не доходит до метода swap, в противном случае деструктор объекта tmp освобождает ресурсы, прежде принадлежавшие текущему объекту (this) (см. идиому RAII).
Приведённая выше реализация также устойчива к присваиваниям объекта самому себе (a=a), однако содержит издержки, связанные с тем, что временная копия в этом случае тоже будет создаваться. Исключить издержки можно дополнительной проверкой:
class Copyable { public: Copyable& operator=(const Copyable &_v) { if(this != &_v) Copyable(_v).swap(*this); return *this;
void swap(Copyable &_v) noexcept;
Многие контейнеры и алгоритмы стандартной библиотеки C++ и библиотеки STL предполагают наличие устойчивого к исключениям оператора присваивания, но без использования идиомы copy-and-swap иногда довольно сложно реализовать такой оператор присваивания для классов, содержащих, например, указатели на экземпляры других классов.
Другие операции Имея функцию-член swap, не генерирующую исключений, можно применять подобную технику, чтобы сделать любую операцию над объектом строгой в отношении к гарантиям безопасности исключений (strong exception-safe guarantee).
Для этого сначала делают копию существующего объекта, выполняют над копией необходимые модификации, а потом меняют *this и временный объект.
если исключение генерирует конструктор копирования, то исходный объект не модифицируется и строгая гарантия безопасности исключений выполняется; если исключение генерируется при изменении временного объекта, то у временного объекта вызовется деструктор и гарантия тоже будет выполнена поскольку исходный объект модифицирован не был; если изменение временного объекта успешно отработало, то срабатывает swap и деструктор временного объекта, не генерирующие исключений.
См. также Идиома noncopyable
Категория:Идиомы программирования Категория:Шаблоны проектирования Категория:Объектно-ориентированное программирование