2015-05-08 3 views
2
#include <iostream> 
class A 
{ 
    public: 
    A() 
    { 
     std::cout << "A()" << std::endl; 
    } 

virtual ~A() 
    { 
     std::cout << "~A()" << std::endl; 
    } 
}; 

class B:public A 
{ 
    public: 
    B() 
    { 
     throw std::exception(); 
     std::cout << "B()" << std::endl; 
    } 

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


int main() 
{ 
    try 
    { 
     B b; 
    } 
    catch(std::exception & e) 
    { 
    } 
    return 0; 
} 

Приведенный выше код выхода,Исключение исключения в конструкторе производного класса. Почему деструктор класса называется деструктором класса, но не производным?

A() 
~A() 

К тому времени, исключение выбрасывается, В был создан. Тогда почему деструктор B не называется?

+2

Вызывается только деструкторы успешно построенных объектов. Другими словами, вы ошибаетесь, говоря, что 'B' был создан к моменту исключения исключения. См. [This] (http://stackoverflow.com/a/10212864/2297365). – huu

ответ

5

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

2

Carlton дает верный ответ. Важное значение имеет эта конструкция (т. Е. Не вызывающая ректор на чем-либо, не полностью построенном). Любой класс C++ может содержать только один ресурс, защищенный деструктором. Например, это не будет работать:

class Ab 
{ 
public: 
      char *m_buff1; 
      char *m_buff2; 

      Ab() { m_buff1 = malloc(100); Xyz(); m_buff2 = malloc(200); } 
     ~Ab() { free(m_buff1); free(m_buff2); } 
}; 

В случае, если исключение произойдет между 2 попытки выделения - нет никакого способа узнать, что безопасно поле инициализируется, а что нет. Я приводил здесь простой пример, чтобы понять суть. Пожалуйста, не комментируйте, что сначала можно инициализировать поля с NULL. Если между mallocs произойдет исключение, первое распределение будет просто пропущено, потому что дескриптор не будет вызван.

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

+0

«Любой класс C++ может содержать только один ресурс, который защищен деструктором». Это не правда. Просто, если в конструкторе выделено более одного ресурса, конструктор должен убедиться, что в случае исключения все уже выделенные ресурсы будут правильно освобождены. Лучший способ убедиться, что это использовать классы RAII, которые справляются с этим. - «Другими словами, лучше избегать проектов, которые бросают исключения из конструкторов». Я не согласен. Написание конструктора, который правильно освобождает ресурсы, совпадает с написанием другой функции, которая правильно освобождает ресурсы. – celtschk

+0

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

+0

Вы советуете не бросать из конструкторов аргумент о том, что вы не можете правильно управлять ресурсами. И я категорически не согласен. – celtschk

Смежные вопросы