Когда функция генерирует ошибку, когда исключение не обработано, раскрутка стека вряд ли сработает, поэтому деструкторы локальных переменных не будут вызываться. Например, следующий код выводит только «созданные» (и сообщения об ошибках) под g ++ 7.1.0:
#include <iostream>
using namespace std;
struct A {
A() { cerr << "created\n"; }
~A() { cerr << "destroyed\n"; }
};
void f() {
A a;
throw 0;
}
int main() {
f();
}
Это может привести к утечке памяти при сбое, если A
выделяет память, и будет ли она освобождена, зависит от ОС.
Возможное решение, которое я нахожу, это f()
в блоке try-catch функции:
void f() try {
A a;
throw 0;
} catch (...) {
throw;
}
Таким образом, деструктор a
всегда называется. Тем не менее, я не нахожу это удовлетворительным, потому что нужно написать пустое предложение catch, а это не так просто.
Итак, что из следующего следует считать правильным, или если есть лучшая практика (особенно при реализации функции в библиотеке)?
Поместите верхний уровень try-catch (…) в свой main
функция, которая выводит сообщение об ошибке и выходит. Это гарантирует, что раскручивание всегда происходит.
Хотя вопрос в том, почему ты этого хочешь. Если вы находитесь в любой реальной среде без встроенной среды, ОС будут очистить все ресурсы вашего процесса. Там нет, может быть, об этом. И поскольку существуют другие способы сбоя процесса, которые не включают исключений, вы все равно не можете полагаться на деструкторы для очистки в таком случае.
Если вы находитесь во встроенной среде, ситуация аналогичная. Возможно, у вас нет операционной системы для очистки, но сбои обычно приводят к перезагрузке устройства, что имеет тот же эффект. И опять же, вы не можете полагаться на деструкторов, потому что есть другие способы сбоя.
Других решений пока нет …