Назад к вопросам
Middle+
166
questionbank
Что такое строгая гарантия исключений и как она реализуется в C++?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Строгая гарантия исключений (Strong Exception Guarantee) означает, что в случае возникновения исключения состояние программы остается неизменным, как если бы операция никогда не выполнялась.
Реализуется чаще всего с помощью идиомы Copy-and-Swap:
- Создается неявная или явная копия объекта.
- Операция выполняется с копией.
- Если операция успешна, состояние исходного объекта атомарно обменивается с состоянием копии (обычно через
swap).
#include <algorithm> // для std::swap
class MyClass {
private:
int* data;
size_t size;
public:
// Конструктор по умолчанию
MyClass() : data(nullptr), size(0) {}
// Конструктор копирования
MyClass(const MyClass& other) : size(other.size) {
data = new int[size]; // Выделение памяти может бросить исключение bad_alloc
std::copy(other.data, other.data + size, data); // Копирование может бросить исключение
}
// Оператор присваивания с использованием идиомы Copy-and-Swap для строгой гарантии
MyClass& operator=(MyClass other) { // Параметр передается по значению, что запускает конструктор копирования
swap(*this, other); // Атомарный обмен состоянием с временным объектом
return *this;
}
// Функция swap
friend void swap(MyClass& first, MyClass& second) noexcept { // swap не должен бросать исключения
using std::swap; // Важно для ADL
swap(first.data, second.data);
swap(first.size, second.size);
}
// Конструктор перемещения
MyClass(MyClass&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
// Деструктор
~MyClass() {
delete[] data;
}
// Пример метода, который может бросить исключение
void resize(size_t new_size) {
// Создаем временный объект с новым размером
MyClass temp;
temp.size = new_size;
temp.data = new int[new_size]; // Может бросить исключение
// Копируем существующие данные (или часть их)
size_t copy_size = std::min(size, new_size);
std::copy(data, data + copy_size, temp.data); // Может бросить исключение
// Если дошли до сюда, операция прошла успешно.
// Атомарно обмениваем состояние.
swap(*this, temp);
}
// Пример метода, изменяющего состояние, который может нуждаться в строгой гарантии
void modify_element(size_t index, int value) {
if (index >= size) {
// Выход за границы, может бросить исключение или обработать иначе
throw std::out_of_range("Index out of bounds");
}
// Прямое изменение без строгой гарантии для этой простой операции
// Для более сложных операций, включающих несколько шагов с потенциальными исключениями,
// могла бы потребоваться Copy-and-Swap.
data[index] = value;
}
// Другие методы...
};
Принцип: все потенциально бросающие исключения операции выполняются на копии. Если исключение происходит, копия (недоделанная) уничтожается, а исходный объект остается в прежнем состоянии. Если операции на копии проходят успешно, состояние исходного объекта обновляется в одном атомарном, не бросающем исключений шаге (обычно swap).