15.3 构建自防御的程序

通常一个缺陷在导致其产生的逻辑错误产生很久以后才会表现出来.如果一个异常的或者不正确的值没有被及时检测到,那么通常在应用程序又执行了几千行代码以后,应用程序才会崩溃或者作出令人费解的表现.为解决这样的问题你可能要花上很长的时间.但是,如果你在你的代码中增加一些普通的检查,来检测函数的某个地方出现了错误的值,那么你的代码将最终变得非常强壮,你将可能避免你和你的用户陷入到大麻烦中去.这就是所谓的自防御程序.你的代码可以防止自己被别的代码或者自己内部的某些错误逻辑搞的一团糟.因为大多数的这些检测在正式发布版中都将被移除,因此,它们占用的系统开销几乎可以忽略不计.

正如你期待的那样,wxWidgets在其内部使用了大量的错误检测代码,你可以在你的代码中直接使用这些宏.这些宏主要分为三类,每一类都有多种形式:第一类是wxASSERT,如果它的参数不等于True,它将显示一个错误信息.这种检测仅存在于调试版本中.wxFAIL则将使用产生一个错误信息,其作用相当于wxASSERT(false).它也仅会存在于调试版本中.wxCHECK则判断条件是否成立,如果不成立则返回某个值并显示错误信息.和前面两种不同的是,在正式版本中,wxCHECK的代码仍然有效,但是将不显示任何消息.

下面的例子演示了怎样使用这些宏:

// 两个正数相加
int AddPositive(int a, int b)
{
    // 检查是否为一个正数
    wxASSERT(a > 0);
    // 检查是否位一个正数,显示定制的消息
    wxASSERT_MSG(b > 0, wxT("The second number must be positive!"));
    int c = a + b;
    // 如果相加的结果不为正数,显示一个错误的消息并且返回-1.
    wxCHECK_MSG(c > 0, -1, wxT("Result must be positive!"));
    return c;
}

你还可以使用wxCHECK2和wxCHECK2_MSG宏,这两个宏在条件不满足的时候可以执行任意的操作而不仅仅是设置一个返回值. 而wxCHECK_RET则可以被用在没有返回值(void)的函数中.另外一些不太常用的宏包括wxCOMPILE_TIME_ASSERT和 wxASSERT_MIN_BITSIZE等,请参考wxWidgets的相关手册.

下图演示了一个断言不满足时显示消息的对话框的样子,在这个对话框上有三个按钮,Yes按钮停止当前程序的运行,No按钮则忽略这个断言失败,而Cancel按钮则表示以后的断言失败都不需要显示.如果程序正运行在某个调试器中,则程序终止运行将返回到调试器中,你可以打印出当前的函数调用堆栈,进而可以知道断言失败的准确位置以及当时各个参数的值.