所谓异常安全的函数是指:即便是在这个函数的调用过程中出现异常,也不会影响到重要的数据或状态。
【异常安全原则】:尽量把可能抛出异常的代码写在函数的最前面,让异常尽量早地抛出,在改变重要数据或状态之前抛出异常。
让我们来比较两段代码:
void f1()
{
importantData.Invalidate();
data = getNewData(); // An exception maybe thrown.
importantData.Set( data );
}
void f2()
{
data = getNewData(); // An exception maybe thrown.
importantData.Invalidate();
importantData .Set( data );
}
在f1()中,importantData的Invalidate发生在getNewData()之前,而后者可能会抛出一个异常,该异常在本函数中没有处理,意味着可能会在调用者的流程中处理。而调用者可能会轻描淡写的处理这个异常,甚至认为importantData没有发生任何变化,继续使用。但实际上它已经无效了,继续使用的结果可能会导致更多的异常出现。
在f2()中,异常在importantData的Invalidate之前就抛出了,如此即便有异常发生,但importantData并没有被改变,外部调用者仍然可以安全的使用它。
当然,我们可以在f1()中加入try …catch块,但这样做与f2相比,实在过于臃肿。就像下面这样:
void f1()
{
importantData.Invalidate();
try
{
data = getNewData(); // An exception maybe thrown.
}
Catch(…)
{
importantData.RestoreData();
}
importantData.Set( data );
}