Ответ
Идиома copy-and-swap — это надежный и эффективный паттерн для реализации оператора присваивания копированием (operator=), обеспечивающий строгую гарантию безопасности исключений и автоматическую поддержку move-семантики.
Суть идиомы: Вместо того чтобы копировать данные внутри operator=, мы создаем временную копию аргумента (используя конструктор копирования или перемещения), а затем обмениваем (swap) её внутреннее состояние с состоянием текущего объекта.
Полная реализация для класса, управляющего ресурсом:
#include <algorithm> // для std::swap
#include <utility> // для std::exchange
class Buffer {
private:
int* data_ = nullptr;
size_t size_ = 0;
// Дружественная функция обмена
friend void swap(Buffer& a, Buffer& b) noexcept {
using std::swap;
swap(a.data_, b.data_);
swap(a.size_, b.size_);
}
public:
// Конструкторы, деструктор...
~Buffer() { delete[] data_; }
// Ключевой метод обмена
void swap(Buffer& other) noexcept {
::swap(*this, other); // Вызов дружественной функции
}
// Оператор присваивания по ИДИОМЕ COPY-AND-SWAP
Buffer& operator=(Buffer other) noexcept { // ПАРАМЕТР ПЕРЕДАЕТСЯ ПО ЗНАЧЕНИЮ!
other.swap(*this); // Обменяли состояние с временной копией
return *this;
// Деструктор 'other' (который теперь содержит старые данные *this)
// автоматически освобождает старый ресурс.
}
// Конструктор копирования (для полноты примера)
Buffer(const Buffer& other) : size_(other.size_) {
data_ = new int[size_];
std::copy(other.data_, other.data_ + size_, data_);
}
// Конструктор перемещения генерируется автоматически или может быть =default
};
Преимущества:
- Безопасность исключений: Вся работа, которая может бросить исключение (выделение памяти, копирование), происходит при создании параметра
otherдо изменения состояния текущего объекта. Если это не удастся,*thisостанется неизменным. - Автоматическая поддержка перемещения: Поскольку параметр передается по значению, компилятор сам вызовет конструктор перемещения для r-value аргументов, делая
operator=универсальным. - Устранение дублирования кода: Логика копирования содержится только в конструкторе копирования.