天天看點

C++異常處理

一 C++異常處理機制

  異常處理基本思想:執行一個函數的過程中發現異常,可以不用再本函數内立即進行處理,而是抛出該異常,讓函數的調用者直接或間接的處理這個問題。

  C++異常處理進制由三個子產品組成:try、throw、catch

  try---catch基本文法:

try 
 { 
可能抛出異常的語句;(檢查) 
} 
catch(類型名[形參名])//捕獲特定類型的異常 
{ 
 //處理1; 
} 
catch(類型名[形參名])//捕獲特定類型的異常 
{ 
 //處理2; 
} 
catch(…)//捕獲所有類型的異常 
{ 
 }       

   示例:

void f1(int i)
{
    if (i<0)
        throw 1;
}
void f2()
{
    f1(-45);
}
void f3()
{
    f2();
}
void f4()
{
    f3();
}
int main()
{
    try{
        f4();
    }
    catch (int i)
    {
        cout <<"error code:"<< i <<"\n"<< endl;
    }
    system("pause");
    return 0;
}      

二 異常捕獲的比對規則

  try塊裡面抛出哪種異常,則catch裡面捕獲哪種類型的異常,一般情況下,類型必須完全比對,但以下三種情況可以進行類型轉換:

  (1)運作從非const對象到const對象轉換,即throw一個非const對象,catch一個const對象

  (2)運作從派生類類型到基類型的轉換

  (3)将數組轉換為數組類型的指針,函數轉換為指向函數類型的指針

#include <math.h>

bool Equal(double num1, double num2)
{
    if (num1 - num2 > -0.0000001 &&
        num1 - num2 < 0.0000001)
    {
        return true;
    }
    else
    {
        return false;
    }
}

// 基數為base為double類型,exponent為整數
double Power(double base, int exponent) // throw(char *)
{
    // 當底數為0且指數為負數時抛出異常
    if (Equal(base,0.0) && (exponent < 0))
    {
        throw exception("base must be positive!"); // thror "error"
    }
    double dbResult = 1.0;
    if (exponent >= 1)
    {
        for (int i = 0; i < exponent; i ++)
        {
            dbResult *= base;
        }
    }
    else if (exponent < 0)
    {
        for (int j = 0; j < abs(exponent); j ++)
        {
            dbResult *= base;
        }
        dbResult = 1/dbResult;
    }
    else if(exponent == 0)
    {
        dbResult = 1;
    }
    return dbResult;
}

void main()
{
    clock_t start,end;
    start = clock();
    try
    {
        cout << Power(0,1) << endl;
        cout << Power(2, 3) << endl;
        cout << Power(-2, 3) << endl;
        cout << Power(2, -3) << endl;
        cout << Power(2, 0) << endl;
        cout << Power(0,-1) << endl;
    }
    catch (exception & e) // char *p
    {
        cout << e.what() << endl;  // cout << p << endl;
    }
    end = clock();
    cout << "程式運作時間:" << (double)(end - start) / CLOCKS_PER_SEC << endl;
    return;
}      

三 異正常範

  (1)函數聲明之後,列出函數可能抛出的異常類型,并保證該函數不會抛出其他類型的異常

    a. void fun() throw(toobig,toosmall,divzero); // 函數抛出指定異常

    b. void f();  // 這意味函數會抛出任何一種異常

    c. void f() throw();   // 這意味函數不會抛出異常

  (2) 保證不在構造函數中抛出異常,因為構造函數的作用是構造對象并初始化,一旦抛出異常,有可能導緻對象不完整或沒有完全初始化

  (3)保證不在析構函數中抛出異常,因為析構函數的作用是完成資源的清理,一旦抛出異常,有可能導緻記憶體洩露等等

四 使用異常的開銷

  當異常被抛出時有相當的運作時間方面的開銷,這就是從來不想把異常用于普通流控制的一部分的原因,而不管它多麼令人心動。設計異常處理的重要目标之一是:在異常處理實作中,當異常不發生時應不影響運作速度,這就是說,隻要不抛出異常,代碼的允許速度如同沒有加載異常處理一樣,無論與否,異常處理都依賴于使用的特定編譯器,異常處理會引出額外資訊,這些資訊被編譯器置于棧上。