Кратко:

Гарантии безопасности исключений обеспечивают корректную работу программы при возникновении исключений. Идиома RAII (Resouce Acquisition Is Initialization) играет ключевую роль в этом процессе.


RAII (Resouce Acquisition Is Initialization) представляет собой идиому программирования, в которой ресурсы автоматически освобождаются при выходе из области видимости. Это обеспечивает гарантии безопасности исключений, предотвращая утечки ресурсов и обеспечивая надежную работу программы при возникновении исключений. Подробнее про идиому RAII - см. RAII.

Гарантии безопасности исключений

Гарантии безопасности исключений классифицируются на три уровня, которые определяют, какие операции могут генерировать исключения и как важно сохранять консистентность данных.

  • Базовые гарантии: Гарантируют, что если исключение возникло, то объекты классов останутся в согласованном состоянии, но не обязательно не изменятся.
  • Сильные гарантии: Гарантируют, что если исключение возникло, то объекты будут в том же состоянии, что и до вызова функции.
  • Безопасные гарантии: Гарантируют, что если исключение возникло, то программа не оставит утечек ресурсов и в общем состоянии не изменится.

Применение идиомы RAII

Идиома RAII помогает обеспечить безопасность исключений путем связывания освобождения ресурсов с жизненным циклом объекта. Это достигается путем использования специализированных классов, называемых обертками ресурсов, которые освобождают ресурсы в своем деструкторе.

Пример кода

#include <iostream>
#include <fstream>
#include <stdexcept>
 
class FileGuard {
public:
    explicit FileGuard(const std::string& filename) : file(filename) {
        if (!file.is_open()) {
            throw std::runtime_error("Failed to open file");
        }
    }
 
    ~FileGuard() {
        if (file.is_open()) {
            file.close();
            std::cout << "File closed\n";
        }
    }
 
    void writeFile(const std::string& data) {
        if (file.is_open()) {
            file << data;
        } else {
            throw std::logic_error("File is not open");
        }
    }
 
private:
    std::ofstream file;
};
 
void writeToFile(const std::string& filename, const std::string& data) {
    FileGuard guard(filename);  // RAII object to manage file resource
    
    guard.writeFile(data);      // Writing data to file
 
    // File will be automatically closed when 'guard' goes out of scope,
    // regardless of whether an exception is thrown or not.
}
 
int main() {
    try {
        writeToFile("example.txt", "Hello, RAII!");
    } catch (const std::exception& e) {
        std::cerr << "Exception occurred: " << e.what() << std::endl;
    }
 
    return 0;
}

В этом примере FileGuard используется для управления доступом к файлу. Конструктор открывает файл, а деструктор закрывает его, обеспечивая надежную работу с файлом даже в случае возникновения исключения в процессе записи.