Вызывается ли деструктор класса C ++, который бросает исключение?

StackOverflow https://stackoverflow.com/questions/3129359

Вопрос

Предположим, у меня есть такой класс:

#include <iostream>

using namespace std;

class Boda {
    private:
        char *ptr;

    public:
        Boda() {
            ptr = new char [20];
        }
        ~Boda() {
            cout << "calling ~Boda\n";

            delete [] ptr;
        }

        void ouch() {
            throw 99;
        }
};

void bad() {
    Boda b;
    b.ouch();
}

int main() {
    bad();
}

Похоже, что деструктор ~Boda Никогда не вызывается, поэтому ptr Ресурс никогда не освобождается.

Вот вывод программы:

terminate called after throwing an instance of 'int'
Aborted

Так что кажется, что ответ на мой вопрос No.

Но я думал, что стек раскручивается, когда исключение было брошено? Почему нет Boda b Объект становится разрушенным в моем примере?

Пожалуйста, помогите мне понять эту проблему ресурсов. Я хочу написать лучшие программы в будущем.

Кроме того, это так называется RAII?

Спасибо, Бода Cydo.

Это было полезно?

Решение

Если исключение в любом месте не поймана, то время выполнения C ++ может свободно идти прямо, чтобы завершить программу, не делая какого-либо раскручивания или вызова ни одного разрушителя.

Однако, если вы добавите блок Try-Catch по вызову bad(), вы увидите деструктор для Boda Объект называется:

int main() {
    try {
      bad();
    } catch(...) {  // Catch any exception, forcing stack unwinding always
      return -1;
    }
}

Рай. означает, что динамически (куча) выделенная память всегда принадлежит автоматически (стек), выделенный объект, который отдал его, когда объект разрушит. Это зависит от гарантии, что деструктор будет вызываться, когда автоматически выделенный объект выходит из природы, будь то из-за нормального возврата или из-за исключения.

Этот угол-корпус обычно не является проблемой в отношении Raii, поскольку обычно главная причина, по которой вы хотите выполнять деструкторы, - это бесплатное память, и вся память возвращается в ОС, когда ваша программа завершится в любом случае. Однако, если ваши деструкторы сделают что-то более сложное, вроде бы, чтобы удалите файл блокировки на диске или что-то, где это будет иметь значение, будь то программа под названием Destructors или нет при сбое, вы можете обернуть main В блоке Try-Catch, который все равно ловит (только для выхода на исключение), просто чтобы убедиться, что стек всегда раскручивается перед завершением.

Другие советы

Разрушитель не будет запущен, если в конструкторе возникает исключение.

Если необходимо будет запустить, если это необходимо (если исключение где-то дебранутся где-то), если исключение поднимается в другом методе, как в вашем примере. Но поскольку программа прекращена, вызов деструктора не нужен здесь и поведение зависит от компилятора ...

Идея RAII Разве этот конструктор распределяет рессор и деструктор освобождает их. Если в конструкторе возникает исключение, нет простого способа узнать, что рессор, где выделены и которые не были (это зависит от точного места в конструкторе, где произошло исключение). Вы также должны помнить, что если конструктор не удается, единственный способ сказать это вызывающему, чтобы вызвать исключение а также Выделенная память освобождается (либо раскручивание стека, либо куча выделенная память), как если бы он никогда не был выделен.

Решение очевидно: если в том случае, если какое-либо исключение может возникнуть внутри конструктора, вы должны поймать его и свободно выделить рессор. Это может быть какой-то дублированный код с деструктором, но это не большая проблема.

В деструкторе вы не должны вызывать исключения, так как он может привести к большим неприятностям с раскручиванием стека.

В любом другом методе используйте исключения, как вам нравится, но не забудьте справиться с ними где-то. Необработанное экспонция может быть хуже, чем никакого исключения вообще. Я знаю о некоторых программах, которые не обрабатывают исключения для некоторых незначительных ошибок ... и сбой на ошибки, которые должны выдавать только предупреждение.

Попробуйте промыть поток - вы увидите, что деструктор действительно называется:

cout << "calling ~Boda" << endl;

Это буферная буксировка ввода / вывода, которая задерживает распечатка до такой степени, что завершение программы разрезается перед фактическим выходом.

Редактировать:

Вышеприведено для Обрабатываемые исключениями. Отказ С участием необработанные исключения Стандарт не указывает, размотана ли стека или нет. Смотрите также Это так вопрос.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top