Почему происходит сбой кода? - PullRequest
0 голосов
/ 26 августа 2009

Глядя в интернете на мозги С ++, я нашел этот пример:

#include <iostream>

using namespace std;

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

    ~A()
    {
        cout << "A::~A()" << endl;
        throw "A::exception";
    }
};

class B {
public:
    B()
    {
        cout << "B::B()" << endl;
        throw "B::exception"; // <- crashes here
    }

    ~B()
    {
        cout << "B::~B()";
    }
};

int main(int, char**) {
    try
    {
        cout << "Entering try...catch block" << endl;

        A   objectA;
        B   objectB;

        cout << "Exiting try...catch block" << endl;
    }
    catch (const char* ex)
    {
        cout << ex << endl;
    }

    return 0;
}

Это то, что я думал, что программа будет делать:

  1. A :: A () будет выводиться на экран при вызове конструктора objectA. Объект А успешно построен.
  2. B :: B () будет выводиться на экран при вызове конструктора объекта B.
  3. Затем конструктор B генерирует исключение. Объект B не построен успешно.
  4. Деструктор объекта B не вызывается, поскольку конструктор никогда не завершался успешно.
  5. Деструктор объекта A будет вызываться при выходе объекта из области действия при выходе из блока try.

Однако, когда я запустил программу, она фактически вылетела в строке, отмеченной знаком <-. Кто-нибудь может объяснить, что именно происходило в тот момент? </p>

Ответы [ 6 ]

11 голосов
/ 26 августа 2009

Если вы действительно кодируете, а не просто загадываете , никогда не бросайте исключения из деструктора . Если во время разматывания стека возникает исключение, вызывается terminate(). В вашем случае деструктор A сгенерировал во время обработки исключение, которое было сгенерировано в конструкторе B.

EDIT: Чтобы быть более точным (как предлагается в комментариях) - никогда не позволяйте исключению избегать деструктора. Исключения, которые попадают внутрь деструктора, не создают проблем. Но если во время разматывания стека программе приходится иметь дело с двумя исключениями - одно, которое вызвало разматывание стека, и то, которое избежало деструктора во время разматывания, std::terminate() идет.

6 голосов
/ 26 августа 2009

Когда B::B() создает исключение, начинается отмотка стека. A::~A() вызывается и выдает другое исключение, которое не перехватывается внутри A::~A().

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

4 голосов
/ 26 августа 2009

Золотое правило в C ++ - деструкторы никогда не должны бросать исключения. Игнорирование этого правила приведет к неопределенному поведению в любых ситуациях.

3 голосов
/ 26 августа 2009

Код вылетает из-за того, что C's C B генерирует исключение, а затем запускает процедуру «разматывания стека»: все локальные объекты уничтожаются, вызывается Dus, D's Dor, и выдает исключение во время разматывания стека, и затем вызывается «abort», потому что не может быть двух исключений одновременно ...

Вывод:

Никогда не выбрасывайте исключение из D'Tor, потому что вы можете бросить его во время разматывания стека.

2 голосов
/ 26 августа 2009

Вы должны НИКОГДА не генерировать исключение в деструкторе. Взгляните на этот вопрос почему.

2 голосов
/ 26 августа 2009

A::~A() вызывается при выходе из блока try именно потому, что объект выходит из области видимости. Вот почему RAII работает - это зависит от вызываемых деструкторов независимо от того, для чего выходит область действия.

A::~A() затем выдает исключение. Поскольку исключение B::B() все еще выбрасывается в стек, это приводит к сбою программы.

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