Кратко:
Гарантии безопасности исключений обеспечивают корректную работу программы при возникновении исключений. Идиома 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
используется для управления доступом к файлу. Конструктор открывает файл, а деструктор закрывает его, обеспечивая надежную работу с файлом даже в случае возникновения исключения в процессе записи.