C++Primer_筆記_異常處理

    異常,當一個函數發現一個無法處理的錯誤時拋出異常,讓函數的

調用者直接或間接的處理這個問題。 

    異常處理,是一種允許兩個獨立開發的程序組件在程序執行期間遇到程序不正常的

情況(稱爲異常,exception )時相互通信的機制。

異常拋出:

throw (表達式)

異常發現與拋出異常:

/*發現異常並且拋出異常*/
try
{
    //可能出現異常的語句
}

捕獲異常:

catch(類型名 + 形參名)    //捕獲特定類型異常
{
    
}
catch(...)           //捕獲任意類型異常(在不確定異常類型時使用) 
{

}

下來看一個簡單的例子:

#include<iostream>
using namespace std;

int Div(int a, int b)
{
    return a/b;
}

int main()
{
    Div(1,0);
    system("pause");
    return 0;
}

結果顯示:

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/7E/96/wKiom1cE0VOjWHJzAABAUomO4h0197.png" title="KY)ZY}`2J7DJK6AQ1}[email protected] " alt="wKiom1cE0VOjWHJzAABAUomO4h0197.png" />

程序直接崩潰,由於調用時傳入第二個參數是零,零不能作除數,所以會崩潰,下面使用異常處理這個問題:

#include <iostream>
#include  <string>
using namespace std;

int Div(int a, int b)
{
    if(b == 0)
    {
	throw string("parameter error.");//異常拋出
    }
    return a/b;
}
int main()
{
    try
    {
    Div(1, 0);//發現異常,與拋出異常
    }
    catch(const string& S)
    {
    	cout<<S<<endl;//捕獲異常
    }
    system("pause");
    return 0;
}

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M01/7E/93/wKioL1cE0v2AFLK9AAAYDl0MYEU208.png" title="LPE`(0HBB~C5]V@_0@22[$L.png " alt="wKioL1cE0v2AFLK9AAAYDl0MYEU208.png" />

程序可以正常運行,也可以看到異常出現的地方,這樣就可以很清楚的解決這個問題。

下面再看個了例子:

#include <iostream>
#include <string>
using namespace std;

void test()
{
    int* p = new int(1);
    if(1)
    {
	throw string("error.");
    }
    delete p;	
}

int main()
{
    try
    {
	test();
    }
    catch(const string& S)
    {
	cout<<S<<endl;
    }
    system("pause");
    return 0;
}

結果顯示:

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M00/7E/97/wKiom1cE3OLBPiwnAAATZfNHtRk356.png" title="%]YI8CTC4U67W{1%H4HH(6P.png" alt="wKiom1cE3OLBPiwnAAATZfNHtRk356.png" />

這個程序運行貌似沒有問題,其實問題大了。

void test()
{
    int* p = new int(1);
    if(1)
    {
	throw string("error.");
	//程序執行到這裏,直接就去catch()那塊了,
	//導致new出來的內存沒有釋放,造成內存泄漏。
    }
    delete p;	
}

內存泄漏:

        會導致你開闢出來的那塊內存以後就不可以用了,這樣多泄漏幾次,你的電腦就哈哈了,會很卡,很卡。

內存泄漏危害:

        從用戶使用程序的角度來看,內存泄漏本身不會產生什麼危害,作爲一般的用戶,根本感覺不到內存泄漏的存在。真正有危害的是內存泄漏的堆積,這會最終消耗盡系統所有的內存。從這個角度來說,一次性內存泄漏並沒有什麼危害,因爲它不會堆積,而隱式內存泄漏危害性則非常大,因爲較之於常發性和偶發性內存泄漏它更難被檢測到。

當然,這裏並不是說內存泄漏,下面可以用異常來處理上面這個問題:

#include <iostream>
#include <string>
using namespace std;

void test()
{
	int* p = new int(1);
	try//發現異常
	{
		if(1)
		{
			throw string("error.");//異常拋出
		}
	}
	catch(...)//捕獲異常
	{
		delete p;//釋放開闢的空間
		throw;//異常重新拋出
	}
	delete p;	
}

int main()
{
	try//發現重新拋出的異常
	{
		test();
	}
	catch(const string& S)//捕獲異常
	{
		cout<<S<<endl;
	}
	system("pause");
	return 0;
}

結果顯示:

650) this.width=650;" src="http://s2.51cto.com/wyfs02/M00/7E/97/wKiom1cE3OLBPiwnAAATZfNHtRk356.png" title="%]YI8CTC4U67W{1%H4HH(6P.png" alt="wKiom1cE3OLBPiwnAAATZfNHtRk356.png" />

這樣就不會出現內存泄漏,也會很清楚的在控制檯顯示錯誤的信息。

異常重新拋出:在異常處理過程中也可能存在單個catch 子句不能完全處理異常的情況。在某些修

正動作之後,catch 子句可能決定該異常必須由函數調用鏈中更上級的函數來處理那麼catch子句可以通過重新拋出(rethrow )該異常把異常傳遞給函數調用鏈中更上級的另一個catch子句,rethrow 表達式的形式爲:

throw;

rethrow 表達式重新拋出該異常對象rethrow 只能出現在catch 子句的複合語句中。被重新拋出的對象就是其原來的異常對象。


棧展開:

    在查找用來處理被拋出異常的catch 子句時因爲異常而退出複合語句和函數定義這個過

        拋出異常的時候,將暫停當前函數的執行,開始查找對應的匹配catch語句。首先檢查throw本身是否在catch塊內部,如果是,再查找匹配的catch語句。如果有匹配的,則處理。沒有則退出當前函數棧,繼續在調用函數的棧中進行查找。不斷重複上述過程。若到達main函數的棧,依舊沒有匹配的,則終止程序。

        上述這個沿着調用鏈查找匹配的catch語句的過程稱爲棧展開。找到匹配的catch語句並處理以後,會繼續沿着catch語句後繼繼續執行。


異常捕獲的匹配規則:

    異常對象的類型與catch說明符的類型必須完全匹配。

    只有以下幾種情況例外:

        1. 允許從非const對象到const的轉換。

        2. 允許從派生類型到基類類型的轉換。

        3. 將數組轉換爲指向數組類型的指針,將函數轉換爲指向函數類型的指針。

異常處理總結:

        異常處理就是通過throw,try,catch,這三個關鍵字,來發現異常,並拋出異常,捕獲異常,可以做出相應的處理。(這只是簡單的異常處理)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章