Item 8 异常安全的ctor和dtor

来源:互联网 发布:淘宝商品地址怎么复制 编辑:程序博客网 时间:2024/05/21 14:00

根据下面的声明,写出实现的代码,要求达到异常安全或异常中立。这意味着即使发生了异常,Stack对象也要处于正确统一的状态。异常要被传递给调用者,让调用者根据上下文处理异常。

 

请思考下面的问题:
● 异常安全的级别有哪些?
● 通用容器是否可以做到“异常中立”(exception neutral)?
● STL里的容器是异常安全,还是异常中立?
● 异常安全是否会影响容器的接口设计?
● 通用容器是否应该有异常列表?

 

 

上面的ctor是异常安全还是异常中立?
假设任意函数都可以抛出异常,那么先要知道都调用了哪些函数。new T[vsize_] 这句先调用了operator new[]()(全局或T的成员函数)申请内存,然后调用vsize_个T的ctor来初始化这些对象。
1> operator new[]()失败时会抛出bad_alloc异常;
2> T的ctor也可以抛出异常,然后系统自动调用dtor把前面构造成功的对象都销毁,最后回收所有内存。
3> 在dtor销毁对象时如果抛出异常,那么系统直接调用terminate中止整个应用程序的执行,更干净。
所以,Stack::Stack()既是异常安全也是异常中立。
1> 如果抛出了bad_alloc异常,则该异常被传递到调用者那里,而没有被本地捕获。这就做到了异常中立。
2> 无论何种异常,最后内存都被回收。这就做到了资源无泄漏。
3> 对象状态能在异常前后保持正确。vsize_虽然被赋值,但是因为对象最后都被销毁了,所以相当于不存在错误对象。

 

 

这样写和上面没什么区别。

再看dtor的实现:

 

那句delete实际上调用了T::~T()和operator delete[]()。后者因为声明的关系不抛出异常:
void operator delete[]( void* ) throw();
void operator delete[]( void*, size_t ) throw();
如果有人重载了它们而抛出了异常,则认为它们犯错!
~T()可能抛出异常,但Stack要求它不抛出。否则,让dtor做到完全的异常安全是不可能的。
换言之,一个类的dtor如果允许抛出异常,那么该类不可能正常工作!保证异常不离开dtor是很重要的。如果你习惯上给每个dtor后面都加上throw(),没问题。这说明你重视这方面。