在派生类构造函数中抛出异常。为什么要调用基类析构函数而不是派生类析构函数?

时间:2015-05-08 00:28:03

标签: c++ exception inheritance

#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。那么为什么B的析构函数不被称为?

2 个答案:

答案 0 :(得分:5)

在构造函数返回之前,对象不被认为是完全构造的,并且不会在不完整的对象上调用析构函数。

答案 1 :(得分:2)

Carlton正在给出正确的答案。这种设计(即没有在没有完全构造的任何东西上调用dector)具有重要的后果。任何C ++类只能包含受析构函数保护的一个资源。例如,这不起作用:

private static void writeXML() {

try {

Document doc = new Document();

Element theRoot = new Element("tvshows");
doc.setRootElement(theRoot);

Element show = new Element("show");
Element name = new Element("name");
name.setAttribute("show_id", "show_001");

name.addContent(new Text("Life on Mars"));

Element network = new Element("network");
network.setAttribute("country", "US");

network.addContent(new Text("ABC"));

show.addContent(name);
show.addContent(network);

theRoot.addContent(show);

//-----------------------------

Element show2 = new Element("show");
Element name2 = new Element("name");
name2.setAttribute("show_id", "show_002");

name2.addContent(new Text("Life on Mars"));

Element network2 = new Element("network");
network2.setAttribute("country", "UK");

network2.addContent(new Text("BBC"));

show2.addContent(name2);
show2.addContent(network2);

theRoot.addContent(show2);

XMLOutputter xmlOutput = new XMLOutputter(Format.getPrettyFormat(), XMLOUTPUT);
//xmlOutput.output(doc, System.out);

xmlOutput.output(doc, new FileOutputStream(new File("./src/jdomMade.xml")));

System.out.println("The file has been written");

}
catch (Exception ex){
    ex.printStackTrace();
}


}

public static final XMLOutputProcessor XMLOUTPUT = new AbstractXMLOutputProcessor() {
@Override
protected void printDeclaration(final Writer out, final FormatStack fstack) throws IOException {
    write(out, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?> ");
    write(out, fstack.getLineSeparator());
}

};

如果在两次分配尝试之间发生异常,则无法安全地知道哪些字段已初始化,哪些不是。我在这里举一个简单的例子来说明问题。请不要评论可以先用NULL初始化字段。如果malloc之间会发生异常 - 第一次分配将被简单泄漏,因为不会调用desctuctor。

换句话说,最好避免从构造函数中抛出异常的设计。更好地考虑使用简单的构造函数来初始化数据字段和单独的方法来分配资源,打开连接等。