🤔 Когда при вызове exception не зовутся деструкторы?В C++ деструкторы объектов вызываются автоматически при выходе из области видимости, даже если выход происходит из-за исключения. Однако есть ситуации, когда деструкторы могут не вызваться, что может привести к утечке ресурсов.
🟠
Динамически выделенные объекты (`new`)Если объект был создан с помощью
new, но перед его удалением произошло исключение, деструктор не вызовется автоматически.
#include <iostream>
class A {
public:
A() { std::cout << "Конструктор A\n"; }
~A() { std::cout << "Деструктор A\n"; }
};
void func() {
A* obj = new A(); // Создаем объект динамически
throw std::runtime_error("Ошибка!"); // Исключение, объект утечет
delete obj; // Никогда не выполнится
}
int main() {
try {
func();
} catch (...) {
std::cout << "Исключение поймано\n";
}
}
Как исправить? Использовать
std::unique_ptr, который автоматически удаляет объект
#include <memory>
void func() {
std::unique_ptr<A> obj = std::make_unique<A>();
throw std::runtime_error("Ошибка!"); // Деструктор вызовется автоматически
}
🟠
Локальные объекты, созданные `new` внутри `try`, но `catch` не обработал исключениеЕсли объект выделяется внутри
try, но исключение не ловится в
catch, программа завершится (
std::terminate), и деструкторы не вызовутся.
void func() {
A* obj = new A();
throw std::runtime_error("Ошибка!"); // std::terminate()
delete obj;
}
int main() {
func(); // Исключение не ловится => программа аварийно завершится
}Как исправить? Нужно обрабатывать исключение на верхнем уровне
int main() {
try {
func();
} catch (...) {
std::cout << "Ошибка обработана\n";
}
}🟠
Исключение в конструктореЕсли исключение возникает в конструкторе, деструктор этого объекта не вызывается, но деструкторы уже созданных объектов будут вызваны.
class B {
public:
B() { std::cout << "Конструктор B\n"; }
~B() { std::cout << "Деструктор B\n"; }
};
class A {
public:
A() {
std::cout << "Конструктор A\n";
throw std::runtime_error("Ошибка в конструкторе A");
}
~A() { std::cout << "Деструктор A\n"; } // Никогда не вызовется!
};
int main() {
try {
B b;
A a; // Исключение в конструкторе A
} catch (...) {
std::cout << "Исключение обработано\n";
}
}Вывод
Конструктор B
Конструктор A
Исключение обработано
Деструктор B
Как исправить? - Использовать концепцию "умные указатели" (
std::unique_ptr), чтобы ресурсы очищались автоматически.
- Переносить ресурсоемкие операции в отдельный метод (
init()), который можно вызывать после конструктора.
🟠
Исключение в деструктореЕсли деструктор объекта бросает исключение, это опасно, особенно если исключение возникло в момент обработки другого исключения.
class A {
public:
~A() {
std::cout << "Деструктор A\n";
throw std::runtime_error("Ошибка в деструкторе!"); // Ошибка
}
};
int main() {
try {
A a;
throw std::runtime_error("Основное исключение");
} catch (...) {
std::cout << "Исключение обработано\n";
}
}Как исправить? Деструкторы не должны выбрасывать исключения. Если исключение возможно, его следует перехватывать внутри деструктора
class A {
public:
~A() {
try {
throw std::runtime_error("Ошибка в деструкторе!");
} catch (...) {
std::cout << "Ошибка подавлена в деструкторе\n";
}
}
};Ставь 👍 и забирай 📚 Базу знаний