C語言和C++都有一個專為調試而準備的工具函數,就是assert()函數。
這個函數實在C語言的assert.h庫檔案裡定義的,是以包含到C++程式裡我們用一下語句:
#include <cassert>
assert()函數需要有一個參數,它将測試這個輸入參數的真or假狀态。
如果為真,Do nothing!
如果為假,Do something!
例子:
#include <cassert>
int main()
{
int a = 20;
assert(a == 65);
return 0;
}
這就出問題了。
我們可以利用它在某個程式裡的關鍵假設不成立時立刻停止該程式的執行并報錯,進而避免發生更嚴重的問題。
另外,除了結合assert()函數,在程式的開發、測試階段,我們還可以使用大量的cout語句來報告在程式裡正在發生的事情。
捕獲異常
同樣為了對付潛在的程式設計錯誤(尤其是運作時的錯誤),捕獲異常是一種完全不同的方法。
簡單來說,異常(exception)就是與預期不相符合的反常現象。
基本使用思路:
1. 安排一些C++代碼(try語句)去嘗試某件事--尤其是那些可能會失敗的事(比如打開一個檔案或申請一些記憶體)
2. 如果發生問題,就抛出一個異常(throw語句)
3. 再安排一些代碼(catch語句)去捕獲這個異常并進行相應的處理。
捕獲異常的基本文法如下:
try
{
//Do something
//Throw an exception on error.
}
catch
{
//Do whatever
}
注意:每條try語句至少要有一條配對的catch語句。必須定義catch語句以便讓它接收一個特定類型的參數。
C++還允許我們定義多條catch語句,讓每條catch語句分别對應着一種可能的異常類型:
catch (int e) {...};
catch (bool e) {...};
catch (...) {...};
最後一條catch語句可以捕獲任何類型的異常。
在程式裡,我們可以用throw保留字來抛出一個異常:throw 1;
在某個try語句塊裡執行過throw語句,它後面的所有語句(截止到這個try語句塊末尾)将永遠不會被執行。
與使用一個條件語句或return語句相比,采用異常處理機制的好處是它可以把程式的正常功能和羅技與出錯處理部厘清晰地劃分開而不是讓它們混雜在一起。
如何讓函數抛出異常
你可以在定義一個函數時明确地表明 你想讓它抛出一個異常,為了表明你想讓它抛出哪種類型的異常,可以使用如下所示文法:
type functionName(arguments) throw(type);
如果沒有這種文法來定義函數,則意味着函數可以抛出任意類型的異常。
注意:有些編譯器可能不支援上述文法,就省略throw(type)。
下面來一個例子:
#include <iostream>
#include <climits>
unsigned long returnFactorial(unsigned short num) throw(const char*); //就是上面說的那個文法,定義一個函數抛出什麼類型的異常,這裡抛出的是char*類型的異常
int main()
{
unsigned short num = 0;
std::cout << "請輸入一個整數:";
while (!(std::cin >> num) || (num < 1))
{
std::cin.clear(); //清除狀态
std::cin.ignore(100, '\n'); //清除緩沖區
std::cout << "請輸入一個整數:";
}
std::cin.ignore(100, '\n');
try
{
unsigned long factorial = returnFactorial(num);
std::cout << num << "的階乘值是:" << factorial;
}
catch (const char *e)
{
std::cout << e;
}
return 0;
}
unsigned long returnFactorial(unsigned short num) throw(const char *)
{
unsigned long sum = 1;
unsigned long max = ULONG_MAX;
for (int i = 1; i <= num; i++)
{
sum *= i;
max /= i;
}
if (max < 1)
{
throw "該基數太大,無法在該計算機中計算出階乘值。\n";
}
else
{
return sum;
}
}
tips
使用異常的基本原則是:應該隻用它們來處理确實可能不正常的情況。
作為一條原則,在構造器和析構器裡不應該使用異常。一位非常有經驗的程式員在這些方法裡成功地使用了異常是可能的,但稍有不慎就會導緻嚴重的問題。
如果try語句塊無法找到一個與之比對的catch語句塊,它抛出的異常将終止程式的執行。
在C++标準庫裡有一個名為exception的檔案,該檔案聲明了一個exception的基類。可是用這個基類來建立個人的子類以管理異常。
有經驗的程式員常常這麼做,而如此抛出和捕獲的是exception類或其子類的對象。
如果你打算使用對象作為異常,請記住這樣一條原則:以“值傳遞”方式抛出對象,以“引用傳遞”方式捕獲對象。