C++異常---總結和相關示例代碼展現

異常基本概念ios

異常即程序在運行期間產生的非預期性錯誤,如內存配額不足、文件不存在、網絡不可用、SQL語句非法等。express

異常分爲可恢復性異常不可恢復性異常網絡

異常是否可恢復,不一樣的應用場景將有不一樣的理解。例如,對於內存配合不足,在短暫的峯涌狀況下內存可以快速恢復則屬於可恢復性異常,由於一但被釋放和回收,程序將回到常態;若內存長時間得不到釋放,則屬於不可恢復性異常,此時應當終止程序的運行。函數

異常又可分爲已知異常和未知異常。已知異常是指程序編寫者事先考慮到的異常,對異常有清晰的定義和處理邏輯,並在程序中進行捕捉;未知異常是指程序編寫者事先未察覺到的異常,能夠理解爲程序bug。this

異常捕獲是一把雙刃劍,對異常進行顯示捕獲,尤爲對於bug型的未知異常,須要找出產生異常的緣由和代碼進行修復,即須要考慮異常的分析定位機制。所以,對於未知異常或者沒法處理的異常,不該當使用catch(…)籠統的進行捕獲,當不須要關心異常或者沒法處理異常的時候,就應該避免捕獲異常或者將未處理的異常再次拋出,以便交由bugreport統一對未處理異常進行捕獲、分析。spa

函數的異常聲明指針

在函數的聲明後面使用throw關鍵字可對函數的異常產生進行限制。code

不容許函數拋出任何異常對象

void f() throw(); 表示f函數不容許拋出任何異常;以VS2005編譯器爲例,若在f函數中拋出異常,編譯時會有以下提示:內存

warning C4297: 'f' : function assumed not to throw an exception but does

1>        __declspec(nothrow) or throw() was specified on the function

但異常仍是能正常拋出和被捕獲。

 

容許函數拋出任意異常

void f() throw(…);表示容許f函數拋出任意異常。

容許函數拋出指定類型的異常

void f() throw(MyException1,MyException2);表示容許函數f拋出MyException1和MyException2兩種類型的異常。以vs2005爲例,在f中拋出其餘類型的異常,編譯未見提示,且異常能正常拋出和被捕獲。

異常的拋出

使用關鍵字throw拋出異常,有以下兩種語法。

throw express;拋出express所表明的表達式的異常,異常類型爲表達式的值的類型,異常的值爲表達式的值。例如,

try{

   throw 10;
}catch(int e){

   //progress....
}

throw;將異常繼續「向上傳遞」。例如,

try{

     throw 10;
}catch(int e){

         throw...
}

異常類型

任何類型均可以做爲異常類型,包括基本數據類型,如int、double、char等;還包括類類型,如std:string;還包括自定義異常類型,即從std::exception派生的子類。

異常對象的傳遞

自定義的異常類:CCustomException

#pragma once

#include <string>
using namespace std;


class CCustomException : public std::exception
{
		public:
			CCustomException(void);
			CCustomException(const char*);
			~CCustomException(void);
		

			std::string getMsg();
			void setMsg(std::string msg);
			virtual const char* what() const;
		private:
			std::string m_msg;
};

#include "StdAfx.h"
#include "CustomException.h"

CCustomException::CCustomException(void)
{
}

CCustomException::~CCustomException(void)
{
}

CCustomException::CCustomException(const char* msg)
{
		m_msg = msg;
}

std::string CCustomException::getMsg()
{
		return m_msg;
}

void CCustomException::setMsg(std::string msg)
{
		m_msg = msg;
}

const char* CCustomException::what() const
{
	 return m_msg.c_str();
}

main函數以下:

// ExceptionExample.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include "CustomException.h"
#include <iostream>

void exceptionTest1()  throw(CCustomException)
{
		throw CCustomException("this is CCustomException Test1!");
		return;
}

void exceptionTest2()  throw(CCustomException*)
{
	throw new CCustomException("this is CCustomException Test2!");
	return;
}

void exceptionTest3()  throw(CCustomException&)
{
	throw(CCustomException("this is CCustomException Test3!"));
	return;
}

void Test1()
{
	try
	{
		exceptionTest1();
	}
	catch (std::exception e)
	{
		cout<<e.what()<<endl;
	}
}

void Test2()
{
	try
	{
		exceptionTest2();
	}
	catch (std::exception *e)
	{
		cout<<e->what()<<endl;
		delete e;
	}
}

void Test3()
{
	try
	{
		exceptionTest3();
	}
	catch (std::exception  &e)
	{
		cout<<e.what()<<endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
		Test1();
		Test2();
		Test3();
	
		getchar();
		return 0;
}

輸出結果以下:

異常對象的傳遞和函數參數的傳遞同樣,有值傳遞、指針傳遞和引用傳遞3種傳遞方式。

值傳遞會產生臨時對象拷貝,且不支持多態。,雖然CCustomException是std::exception的子類,可是仍然不能調用CCustomException的what函數,輸出了Unknown Message。

指針傳遞

指針傳遞能夠實現多態,但會將臨時對象的地址做爲指針傳出去,出現懸掛指針錯誤。若是在堆上分配內存空間,又不知道什麼時候恰當的刪除對象,二來代碼可讀性、可維護性遭到破壞,違反了內存空間從哪裏申請獲得就在哪裏釋放的內存分配釋放原則。

值引用傳遞既能避免臨時對象的拷貝,又能支持多態,且沒有對象釋放問題。推薦採用值引用的方式傳遞異常對象。輸出結果爲:This is CCustomException Test3.

catch的匹配規則

異常匹配採用自底向上的匹配順序進行匹配,即先在異常產生的函數中進行匹配,若該形成該異常的代碼沒有被try…catch…捕獲或者catch類型不匹配,則向上傳遞直到匹配到第一條catch結束匹配,或則未發現任何匹配的catch則產生未處理異常交由運行時環境處理。

對於基本數據類型的異常,採用嚴格類型匹配機制,不支持類型轉換

對於自定義類型,基類類型可以匹配子類異常對象,子類類型不能匹配基本異常對象。

C++提供了強大的異常處理機制將異常產生和異常處理的代碼分離,即將程序的正常業務邏輯和錯誤處理邏輯進行分離,並在不改變函數原型的狀況下,實現異常對象的「向上」傳遞。

C++的異常處理機制有3部分組成:try(檢查),throw(拋出),catch(捕獲)。把須要檢查的語句放在try模塊中,檢查語句發生錯誤,throw拋出異常,發出錯誤信息,由catch來捕獲異常信息,並加以處理。通常throw拋出的異常要和catch所捕獲的異常類型所匹配。異常處理的通常格式爲:

try
  {
    被檢查語句
    throw 異常
  }
  catch(異常類型1)
  {
    進行異常處理的語句1
  }
  catch(異常類型2)
  {
    進行異常處理的語句2
  }
相關文章
相關標籤/搜索