2014-05-20 59 views
2

这是post的后续问题。请参阅此问题的结尾,了解“函数尝试块”的定义。为什么我们需要一个函数try块?

问题:如果函数try块没有“处理”在构造函数中引发的异常,为什么我们最终需要它们?你能举一个例子来利用函数try块吗?

考虑下面的代码。

#include <iostream> 
#include <new> 
#include <exception> 
using namespace std; 

struct X { 
    int *p; 
    X() try : p(new int[10000000000]) {} 
    catch (bad_alloc &e) { 
    cerr << "exception caught in the constructor: " << e.what() << endl; 
    } 
}; 

int main() { 
    try { 
    X x; 
    } 
    catch (exception &e){ 
    cerr << "exception caught outside the constructor: " << e.what() << endl; 
    } 
    return 0; 
} 

输出是

exception caught in the constructor: std::bad_alloc exception caught outside the constructor: std::bad_alloc

在我看来,无论我在功能try块做,异常总是要被抛出到调用外部范围构造函数,例如上述代码中的X x;

“function try block”的定义,摘自“C++ Primer 5th”。

要处理来自构造函数初始值设定项的异常,我们必须将构造函数作为函数try块写入。函数try块允许我们将一组catch子句与构造函数的初始化阶段(或析构函数的销毁阶段)以及构造函数的(或析构函数的)函数体相关联。

回答

3

你说得对,总是传播异常。

函数try块允许您捕获该异常,例如销毁作为参数传递的对象(也许这是一个智能指针类?),而不引入人造基类。

更一般地说,它使您能够清理由函数调用引入的状态更改。


对于一个构造的情况下:

随着异常传播的析构函数被称为对于所有成功构建子对象,其中包括基类的子对象(如果有的话)。

但是,这个不完全构造的对象自己的析构函数没有被调用。函数try块理想情况下不是用于执行那些会在析构函数中执行的操作的设备。未完全创建的对象自己的析构函数无关紧要,因为它的任务是清除由构造函数主体和/或稍后的成员函数调用引入的状态更改,并且使用通用的“零规则”设计,不存在如然而。

2

当构造函数抛出时,相应的析构函数不会运行。这就是你书中引用的原因:清理必须由构造函数本身来完成。

但您的示例显示异常传播。这是必要的,因为构造函数失败了,因此没有创建对象。调用代码不应该像构造函数创建对象一样进行。

相关问题