天天看點

合理使用c++異常處理機制

c++提供了異常處理機制。

它的優點:

(1)正常流程與異常流程分開處理。邏輯上更清晰。

(2)不使用異常機制,就要在調用函數堆棧中一系列函數中編寫大量判斷語言,幹擾正常流程邏輯。

實際測試代碼 

見 http://blog.csdn.net/zjplus/article/details/2541143

//normal.cpp
#include <iostream>
#include <ctime>

using namespace std;


void normal(const int count)
{
	long k = 0;
	clock_t start = clock();

	for (int j=0; j<count; j++)
	{
		k++;
		k = k % count;
	}

	clock_t end = clock();
	double last_time = double(end - start) / CLOCKS_PER_SEC;
	cout<<"normal() last time is "<<last_time<<endl;
	cout<<k<<endl;         // 防止for循環被優化了
}

int main(int argc, char **argv)
{
	int count = 50000000;

	normal(count);

	cin.get();
	return 0;

};
           
//try_with_no_exception.cpp
#include <iostream>
#include <ctime>
using namespace std;

void try_with_no_exception(const int count)
{
	long k = 0;
	clock_t start = clock();

	for (int j=0; j<count; j++)
	{
		try
		{
			k++;
			k = k % count;
		}
		catch (int e)
		{
			/// do nothing
		}
	}

	clock_t end = clock();
	double last_time = double(end - start) / CLOCKS_PER_SEC;
	cout<<"try_with_no_exception() last time is "<<last_time<<endl;
	cout<<k<<endl;         // 防止for循環被優化了
}

int main(int argc, char **argv)
{
	int count = 50000000;
	try_with_no_exception(count);
	cin.get();
	return 0;
};
           
//try_with_exception.cpp
#include <iostream>
#include <ctime>
using namespace std;

void try_with_exception(const int count)
{
	long k = 0;
	clock_t start = clock();
	for (int j=0; j<count; j++)
	{
		try
		{
			k++;
			k = k % count;
			throw 10;
		}
		catch (int e)
		{
		/// do nothing
		}
	}
	clock_t end = clock();
	double last_time = double(end - start) / CLOCKS_PER_SEC;

	cout<<"try_with_exception() last time is "<<last_time<<endl;
	cout<<k<<endl;         // 防止for循環被優化了
}
int main(int argc, char **argv)
{
	int count = 5000;
	try_with_exception(count);
	cin.get();
	return 0;
};
           

時間對比

函數名 是否開啟異常 循環次數 時間(s)
normal 五千萬次 0.985
normal 五千萬次 0.985
try_with_no_exception 五千萬次 1.016
try_with_exception.cpp 五萬次 38.078

由對比資料可得出如下結論

運作帶有異常的代碼函數,當不抛出異常時,其運作效率與沒有異常代碼的函數,效率上幾乎沒有差别。

運作時大量抛出異常會嚴重影響程式效率。

是以,若在c++使用異常,則要示使用異常機制的代碼,執行機率要非常小。

附:

google 的c++異常的觀點

不要使用C++異常。 

優點: 1) 異常允許上局應用決定如何處理在底局嵌套函數中収生的“不可能發生”的失敗,不像出錯代碼的記彔那麼模糊費解;

 2) 應用亍其他徆多現代語言中,引入異常使得C++與Python、Java及其他與C++相近的語言更加相容;

 3) 許多C++第三方庫使用異常,關閉異常将導緻難以與之結合; 

4) 異常是解決構造函數失敗的唯一方案,雖然可以通過工廠函數(factory function)或Init()方法模拟異常,但他們分别需要堆配置設定新的“非法”狀态;

 5) 在測試架構(testing framework)中,異常确實很好用。

 缺點: 1) 在現有函數中添加throw語句時,必須檢查所有調用處,即使它們至少具有基本的異常安全保護,或者程式正常結束,永迖不可能捕獲該異常。

例如:如果f()依次調用了g()和h(),h抛出被f捕獲的異常,g就要當心了,避免沒有完全清理;

 2) 通俗一點說,異常會導緻程式控制流(control flow)通過檢視代碼無法确定:函數有可能在不确定的地方傳回,進而導緻代碼管理和調試困難,當然,你可以通過規定何時何地如何使用異常來最小化的降低開銷,卻給開發人員帶來掌撐這些規定的負擔;

3) 異常安全需要RAII和不同編碼實踐。輕松、正确編寫異常安全代碼需要大量支撐。允許使用異常;

 4) 加入異常使二進制執行代碼體積變大,增加了編譯時長(或許影響不大),還可能增加位址空間壓力; 

5) 異常的實用性可能會刺激開發人員在不恰當的時候抛出異常,或者在不安全的地方從異常中恢複,例如,非法使用者輸入可能導緻抛出異常。如果允許使用異常會使得返樣一篇程式設計風格指南長出很多(譯者注,返個理由有點牽強)

 結論: 從表面上看,使用異常利大亍弊,尤其是在新項目中,然而,對亍現有代碼,引入異常會牽還到所有依賴代碼。如果允許異常在新項目中使用,在跟以前沒有使用異常的代碼整合時也是一個麻煩。因為Google現有的大多數C++代碼都沒有異常處理,引入帶有異常處理的新代碼相當困難。 鑒于Google現有代碼不接受異常,在現有代碼中使用異常比在新項目中使用的代價多少要大一點,遷移過程會比較慢,也容易出錯。我們也不相信異常的有效替代方案,如錯誤代碼、斷言等,都是嚴重負擔。 我們并不是基于哲學或道德局面反對使用異常,而是在實踐的基礎上。因為我們希望使用Google上的開源項目,但項目中使用異常會為此帶來不便,因為我們也建議不要在Google上的開源項目中使用異常,如果我們需要把返些項目推倒重來顯然不太現實。 對于Windows代碼來說,這一點有個例外(等到最後一篇吧:D)。 注:對于異常處理,顯然不是短短幾句話能夠說清楚的,以構造函數為例,很多C++書籍上都提到當構造失敗時隻有異常可以處理,Google禁止使用異常返一點,僅僅是為了自身的友善,說大了,無非是基亍軟體管理成本上,實際使用中還是自己決定。