异常是比较复杂的一个问题。但是一般来说,异常分为两种:
基本保证和强烈保证。基本保证就是指内存不泄露等,强烈保证指程序的状态没有改变。
看看下面一个例子:
class A{ };
class B{
A* p;
public:
B()p(new A){}
}
这儿 new可以抛出异常,但是new分为两个动作,一个动作时分配内存,另外一个动作构造对象。
如果在分配内存时候出错,那么不会内存泄露,因为内存根本就没有分配成功,所以不会泄露。
如果是在构造对象时候出错,那么由编译器调用delete,这样也不会发生内存泄露。
但是,有下面一种情况:
A* m_p = new A;
....
//在这儿抛出异常。
delete m_p;
上面的代码就会导致内存泄露,因为还没有到delete,就抛出了异常,代码根本执行不到delete m_p去,所以就内存泄露了。
这样传说中的boost::shared_ptr就派上了用场了。
int a;
boost::shared_ptr <A>m_p(new A);
......
//抛出异常。
因为boost::shared_ptr是一个栈对象,即便是抛出了异常,但是系统会按照栈的方式销毁。
| m_p |
| a |
栈的方式是先进后出,故a在下面。即便抛出了异常,但是影响不到栈的释放,这是由系统来完成。
对于堆就不同了。
还有一种情况就是当有两个以上的shared_ptr
作为函数参数时,这种情况不是强烈保证的:
class A{};
class B:public A{};
fun(shared_ptr <A>, shared_ptr <B>);
再构造上面这个表达式时,可以是这个顺序:
A分配内存;
B分配内存;
A构造对象;
B构造对象;
shared_ptr <A>;
shared_ptr <B>;
假如在步骤B构造对象时抛出异常,那么A的内存无法释放。这样就内存泄露了。
因此,这种用法不是异常强烈保障的。