2014-10-07 52 views
2

我有这个程序,派生类的ctor抛出异常。该程序只是一个示例程序,我只是想了解异常处理的概念。类的构造函数中异常处理的行为

class A{ 
public: 
    A() {} 

    ~A(){std::cout << "DTOR called - A!!" << std::endl;} 
}; 

class B : public A 
{ 
public: 
    B():A() 
    { 
     try 
     { 
     init(); 
     } 
     catch(...) 
     { 
     std::cout << "Inside catch block in B's Ctor!!" << std::endl; 
     throw this; 
     } 
    } 

    void init() { throw 0; } 

    ~B() {std::cout << "DTOR called - B!!" << std::endl; } 
}; 

int main() 
{ 
    try{ 
     B *b = new B; 

     std::cout << "Äfter B's ctor called in try block!!" << std::endl; 
     delete b; 
     std::cout << "Äfter B's dtor called in try block!!" << std::endl; 
    } 

    catch(B* b) 
    { 
     delete b; 
     b = NULL; 
     std::cout << "Exception Occurred in B!!" << std::endl; 
    } 

    catch(A* a) 
    { 
     delete a; 
     a = NULL; 
     std::cout << "Exception Occurred in A!!" << std::endl; 
    } 

    catch(...) 
    { 
     std::cout << "Exception Occured!!" << std::endl; 
    } 
    return EXIT_SUCCESS; 
} 

预期的输出是它应该进入B的catch块,并且应该调用第一个B的dtor,然后调用A的dtor。但上述程序的输出是:

Inside catch block in B's Ctor!! 
DTOR called - A!! 
DTOR called - B!! 
DTOR called - A!! 
Exception Occurred in B!! 

我想问这是为什么A类的析构函数调用了两次,当它只是引入了B类的catch块,并呼吁只有B类的析构函数? 也请告诉我是否在这里犯了一些错误。 任何帮助表示赞赏

编辑:

class B : public A 
{ 
public: 
    B():A() 
    { 
     try 
     { 
     szName = new char[100]; 
     init(); 
     } 
     catch(...) 
     { 
     std::cout << "Inside catch block in B's Ctor!!" << std::endl; 
     throw this; 
     } 
    } 

    void init() { throw 0; } 

    ~B() 
    { 
     delete szName; 
     std::cout << "DTOR called - B!!" << std::endl; 
    } 

    char *szName; 
}; 

在这里,我在构造函数try块创建了一个字符指针类B.分配的内存被抛出异常之前。现在在这种情况下,如果我没有发现类B的异常,会不会有内存泄漏?

+0

见http://www.gotw.ca/gotw/066.htm – 2014-10-07 06:33:29

回答

2

~A()被调用两次的原因是因为B()体内,A()完全初始化,所以在发生异常时,~A()将自动被调用,而B()本身还没有完全初始化,因此~B()不会被调用,并且如果构造函数抛出,则不必删除指针,C++将在这种情况下为您调用delete。见LIVE DEMO

3

你为什么要在你的catch块中扔“this”?你已经在试图制造“这个”的时候进行了尝试,那么你怎么能把它扔掉呢?尝试扔掉你抓到的东西,或者其他的东西,比如“糟糕”。

+0

我扔“本”,否则这将是一个内存泄漏。你将如何删除分配给“b”的内存呢? – 2014-10-07 06:25:38

+0

不是问题,除非在抛出之前已经在构造函数中分配了某些东西。 – 2014-10-07 06:28:34

+0

@SaurabhBhola:如果构造函数抛出,'new'会自动释放它分配的内存。没有必要尝试自己做。 – 2014-10-07 06:36:21

3

不要抛弃this:在发现异常时,失败的对象不再存在。它已被清除,析构函数调用其成员和基类,并且其内存由异常处理机制自动解除分配。试图第二次删除它是一个错误。

就像从任何其他函数中抛出正常的异常类型(最好是std::exception的子类型)。

0

1)B * b = new B;

竣工类的

类B的结构是不完整的

2)抛出此;

它会释放类的部分,所以〜A()被调用,〜B()不会被调用,因为它的结构是不完整的

3)控制进入赶上(B * B)

删除b;

称为〜然后B〜一个

相关问题