Исключения - c ++ - PullRequest
       12

Исключения - c ++

2 голосов
/ 14 сентября 2010

Я пытаюсь понять поведение исключений в C ++. Я написал следующий код:

class A{
public: 
    A(){
    };
    ~A(){
        cout<<"hello";

    };
};
int exceptionTest(){

    throw "blablabla";
};

int main(){

        A sd;
    int test = exceptionTest();
     return 0;
}

Я заметил, что в этом случае вызывается distructor, хотя никто не поймал исключение. Если я изменю «основной» код на:

 int main(){

            A* sd = new A();
        int test = exceptionTest();
         return 0;
    }

Диструктор не будет вызван. Может кто-нибудь сказать мне, в чем причина такого поведения?

Спасибо, Li

Ответы [ 5 ]

8 голосов
/ 14 сентября 2010

То, что вы бросаете исключение, здесь не имеет значения. В вашем первом примере sd - это объект, который существует в стеке. Когда исполнение по какой-либо причине выходит из своей области, оно уничтожается. Во втором примере sd - это указатель на объект, который был явно выделен с использованием new. Этот объект не будет уничтожен, пока этот указатель не будет передан delete; поскольку вы никогда этого не делаете, ваша программа в настоящее время пропускает ее.

4 голосов
/ 14 сентября 2010

Стандарт может сказать следующее по этому вопросу:

-9- Если в программе не найден соответствующий обработчик, вызывается функция terminate(); независимо от того, разматывается ли стек до того, как этот вызов terminate() определяется реализацией .

Таким образом, ваш компилятор выполняет разматывание стека (вызывая деструкторы локальных объектов), другие могут не,Например, на G ++ или codepad.org эта программа не выведет "привет".


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

2 голосов
/ 14 сентября 2010

Я заметил, что в этом случае вызывается distructor, хотя никто не поймал исключение.

Это именно то, чего ожидать.

Этот механизм является следствием RAII, который делает вас «уверенными», что ресурсы будут освобождены, даже если есть исключение. Например:

class File
{
   public:
   File( const std::string filename ) : file_handler(file_open( filename )) { } // whatever the implementation

   ~File() { file_close(file_handler); }

   private:
   FileHandler file_handler;
};

void test(){ throw "This is a test"; }


int main()
{
   File file("test.txt");
   test();
   return false;
}

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

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

2 голосов
/ 14 сентября 2010

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

0 голосов
/ 14 сентября 2010

Это не совсем ответ, но я мог бы уточнить поведение, в случае механизма RAII, которое я понял из другого ответа и комментариев Майка.

#include <iostream>

class Bar
{
        public:
        Bar() { std::cout << "Bar constructor" << std::endl; }
        ~Bar() { std::cout << "Bar destructor" << std::endl; }
};

void foo()
{
        throw("Exception");
}

int main()
{
        // Variation, add { to create a new scope
        Bar bar;
        foo();
        // Variation : }
        return 0;
}

Используя g++, этот кодтам, где исключение не перехвачено, будет выведено следующее:

Bar constructor
terminate called after throwing an instance of 'char const*'
Aborted

Это означает, что g++ не разматывает стек (или не выводит переменную из области видимости, если я правильно понимаю «вариант»), поэтому деструктор не вызывается.

Однако, если вы поймаете исключение:

#include <iostream>

class Bar
{
        public:
        Bar() { std::cout << "Bar constructor" << std::endl; }
        ~Bar() { std::cout << "Bar destructor" << std::endl; }
};

void foo()
{
        throw("Exception");
}

int main()
{
        try
        {
                Bar bar;
                foo();
        }
        catch (...)
        {
                // Nothing here
        }
        return 0;
}

, тогда будет вывод

Bar constructor
Bar destructor

, и вы восстановите правильныйповедение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...