Interested Article - Copy-and-swap
- 2021-02-15
- 1
Идиома 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 и деструктор временного объекта, не генерирующие исключений.
См. также
|
В статье
не хватает
ссылок на источники
(см.
рекомендации по поиску
).
|
- 2021-02-15
- 1