бросить исключение из конструктора в C ++ - PullRequest
8 голосов
/ 10 марта 2012

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

#include <iostream>
using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    E e;
}


$ g++ test.cpp; ./a.exe
C
C
E
terminate called after throwing an instance of 'int'
Aborted (core dumped)

В этом случае конструктор E выдает исключение, но деструктор C как элемент данных или базовый класс не вызывается. Теперь, если деструктор C выполняет некоторые операции очистки, такие как закрытие файлов / сокетов и удаление выделений из кучи, это может вызвать проблемы.

Итак, мой вопрос: почему и когда можно генерировать исключения из конструкторов?

Ответы [ 4 ]

12 голосов
/ 10 марта 2012

Если вы поймаете ошибку, деструктор будет запущен.Когда в C ++ создается неперехваченное исключение, среда выполнения вызывает std::terminate.По умолчанию std::terminate вызывает std::abort, что определенно не вызывает деструкторов при выходе.

С этой версией:

#include <iostream>
using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    try {
        E e;
    } catch(...) {
    }

    return 0;
}

Я получаю вывод:

C
C
E
~C
~C
2 голосов
/ 10 марта 2012

Я заметил, что он не вызывает деструктор базового класса или его членов данных, если из конструктора выдается исключение

Да, это так.

Однако , поскольку вы не catch это исключение во всей программе, программа немедленно завершается .

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

1 голос
/ 26 октября 2013
1) E's constructor catched the exception and ran completly.
   Therefore, its object is created and the distructor is 
   invoked.

struct C
{
    C() {cout <<__FUNCTION__<< endl;}
    ~C() {cout <<__FUNCTION__<< endl;}
};

struct E: public C
{
    C c;
    E() { 
    try {
        cout <<__FUNCTION__<< endl; 
        throw 4;
    }
    catch(int i) {
    cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
    }   
}
    ~E() {cout << __FUNCTION__ << endl;}
void print(){
    cout<<"obj of class E is created"<<endl;
}
};

int main()
{
    try {
       E e;
   e.print();
} 
catch(int i) {
   cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
    }

    return 0;
}

/*
Results:
C::C
C::C
E::E
int 4 is catched by E::E
obj of class E is created
E::~E
C::~C
C::~C
*/

2) E's constructor didn’t catch the exception and ran incompletly.
   In result, its object is not created. Therefore, its distructor
   is not invoked.

struct C
{
    C() {cout <<__FUNCTION__<< endl;}
    ~C() {cout <<__FUNCTION__<< endl;}
};

struct E: public C
{
    C c;
    E() { 
   try {
      cout <<__FUNCTION__<< endl; 
      throw 4;
   }
   catch(float i) {
      cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
   }    
}
    ~E() {cout << __FUNCTION__ << endl;}
void print(){
    cout<<"obj of class E is created"<<endl;
}
};

int main()
{
    try {
        E e;
    e.print();
} 
catch(int i) {
   cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
    }

    return 0;
}

/*
Results:
C::C
C::C
E::E
C::~C
C::~C
int 4 catched by main function
*/
1 голос
/ 10 марта 2012

Вы не обрабатываете "исключение".

> cat test.cpp
#include <iostream>

using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    try
    {
        E e;
    }
    catch (int i)
    {
        std::cerr << "Handled " << i << std::endl;
    }
}

Сборка и запуск ..

> make test
make: `test' is up to date.
> ./test
C
C
E
~C
~C
Handled 4
> 

Обе C s разрушены и совершенно нормальное завершение.

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