Что такое идиома Copy-and-Swap в C++ и когда её использовать?
Что такое Copy-and-Swap?
Copy-and-Swap — это идиома C++, которая позволяет реализовать оператор присваивания безопасно и элегантно, используя копирующий конструктор и функцию обмена (swap). Основная идея: мы создаём временную копию объекта, а затем обмениваем её содержимое с текущим объектом. Деструктор временного объекта автоматически очистит старые данные.
Почему это безопаснее?
Ваш текущий код имеет несколько проблем:
- Исключения при выделении памяти: если
newвыбросит исключение, объект останется в повреждённом состоянии (уже удалённые данные). - Дублирование логики: копирование данных повторяется в конструкторе и операторе присваивания.
- Проверка на самоприсваивание: хоть и не обязательна, но многие её добавляют "на всякий случай", замедляя код.
Copy-and-Swap решает все эти проблемы одной простой техникой.
Реализация для вашего класса
Сначала нам нужна функция swap (можно сделать другом класса):
class MyArray {
int* data;
size_t size;
public:
// Дружественная функция swap для быстрого обмена
friend void swap(MyArray& first, MyArray& second) noexcept {
using std::swap;
swap(first.data, second.data);
swap(first.size, second.size);
}
// Конструктор остаётся без изменений
MyArray(size_t s) : size(s), data(new int[s]) {}
// Копирующий конструктор (нужен обязательно)
MyArray(const MyArray& other) : size(other.size), data(new int[other.size]) {
std::copy(other.data, other.data + size, data);
}
// Деструктор
~MyArray() { delete[] data; }
// Оператор присваивания — теперь одна строка!
MyArray& operator=(MyArray other) { // Принимаем по значению!
swap(*this, other); // Обмениваем содержимое
return *this;
}
};
Как это работает?
- Параметр по значению:
MyArray otherсоздаётся через копирующий конструктор (или перемещающий, если есть). Если копирование выбрасывает исключение — оно происходит до входа в функцию, и наш объект остаётся нетронутым. - Обмен:
swap(*this, other)меняет местами data и size текущего объекта и временной копии. Теперь*thisвладеет новыми данными, аother— старыми. - Автоматическая очистка: при выходе из функции временный объект
otherуничтожается, его деструктор освобождает старую память.
Преимущества
- Исключительная безопасность: если копирование не удалось — оператор присваивания даже не вызывается.
- Нет дублирования: логика копирования живёт только в конструкторе.
- Самоприсваивание безопасно: проверка не нужна, так как обмен с самим собой — это просто обмен указателей.
- Единая точка изменения: хотите добавить поле? Обновите конструктор копирования и swap — оператор присваивания сам подстроится.
Важное замечание
Для классов с ресурсами, которые не копируются (например, файловые дескрипторы), идиома также работает, но нужно реализовать перемещающий конструктор и swap. В современном C++ (C++11 и новее) это стандартный подход для "правила пяти".
<<Ответов пока нет.
Войдите чтобы оставить ответ