В чем заключается особенность выбрасывания исключений в конструкторах и деструкторах?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Выбрасывание исключений из конструктора приводит к тому, что объект не будет полностью создан. В этом случае автоматически вызываются деструкторы для всех уже проинициализированных подобъектов (членов-данных и базовых классов).
Выбрасывание исключений из деструктора крайне нежелательно. В случае, если исключение выбрасывается во время обработки другого активного исключения (например, при раскрутке стека), программа завершится вызовом std::terminate. Даже в отсутствие другого активного исключения, выброс исключения из деструктора может нарушить ожидаемый поток выполнения и сделать код непредсказуемым. Рекомендуется обрабатывать все исключения внутри деструктора или проектировать код так, чтобы деструктор не мог выбросить исключение.
#include <iostream>
#include <stdexcept>
class Resource {
public:
Resource() {
std::cout << "Resource acquired" << std::endl;
}
~Resource() noexcept { // Деструктор не должен выбрасывать исключения
try {
// Потенциально опасная операция, которая может выбросить исключение
// std::cout << "Resource released (potentially throwing op)" << std::endl;
// throw std::runtime_error("Error during release");
std::cout << "Resource released" << std::endl;
} catch (...) {
// Логирование или другая обработка ошибки без повторного выброса
std::cerr << "Exception caught in Resource destructor!" << std::endl;
// std::abort(); // Крайний случай для неисправимых ошибок
}
}
};
class MyClass {
private:
Resource res1;
Resource res2; // Этот ресурс будет создан после res1
Resource res3;
public:
MyClass(int value) : res1(), res2(), res3() {
std::cout << "MyClass constructor started" << std::endl;
if (value < 0) {
// Исключение в конструкторе
// res1 и res2 уже созданы и будут автоматически уничтожены
throw std::runtime_error("Negative value not allowed");
}
std::cout << "MyClass constructor finished" << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor called" << std::endl;
// Деструкторы res1, res2, res3 будут вызваны автоматически
}
};
int main() {
try {
MyClass obj1(10); // Успешное создание
} catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
std::cout << "---" << std::endl;
try {
MyClass obj2(-5); // Исключение в конструкторе
} catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
std::cout << "---" << std::endl;
// Пример с потенциальным исключением в деструкторе (закомментировано)
// MyClass obj3(20);
// (объект obj3 будет уничтожен при выходе из main, вызывая деструктор)
return 0;
}