欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中的異常實例詳解

 更新時間:2022年02月07日 15:59:17   作者:wuqiongjin  
異常處理是C++的一項語言機制,用于在程序中處理異常事件,下面這篇文章主要給大家介紹了關(guān)于C++中異常的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

1. 異常

異常: 異常是面向?qū)ο笈c法處理錯誤的一種方式

1.1 C語言中處理錯誤的方式

  • 返回錯誤碼 (很多API接口都會把錯誤碼放到errno當中)
  • 終止程序 (assert終止、除零錯誤、段錯誤) [產(chǎn)生信號去終止進程]
  • C標準庫中setjump和longjump組合

1.2 C語言處理錯誤方式的缺陷

  • 使用錯誤碼時,還需要查看錯誤碼表,去找每個錯誤碼的含義
  • 當一個函數(shù)是通過返回值去輸出數(shù)據(jù),那么發(fā)生錯誤的時候很難處理 (不好區(qū)設置發(fā)生錯誤時返回什么)
  • 如果調(diào)用的函數(shù)棧很深時,使用錯誤碼去一層層返回時,處理起來很麻煩
//第2點
T& operator[](int index)
{
	//問題: 當訪問的下標index超出容器的范圍,此時該返回什么值?
    //解決方案: 可以再傳一個參數(shù),用于獲取真正的結(jié)果(當輸出型參數(shù)), 返回值就用于判斷是否正確的返回了. 
    //實際上還是很麻煩
}

2. C++異常

2.1 異常相關(guān)關(guān)鍵字

  • try: try塊中放置可能會拋出異常的代碼,這段代碼被稱為保護代碼
  • catch: catch用于捕獲異常,catch塊中寫處理異常的代碼。它跟在try的后面,1個try后面可以跟多個catch
  • throw: throw用于拋出異常
try
{
    //保護代碼(可能會拋出異常的代碼)
}catch(ExceptionType e1)
{
    //處理異常
}catch(ExceptionType e2)
{
    //處理異常
}catch(ExceptionType eN)
{
    //處理異常
}

2.2 異常的使用

2.2.1 異常的拋出和匹配原則

  1. 異常是通過拋出對象而引發(fā)的,該對象的類型決定了應該匹配到哪個catch塊
  2. 異常的拋出會去匹配在整個調(diào)用鏈中與該對象類型相匹配且距離最近的那個
  3. 當異常拋出后,執(zhí)行流會直接跳轉(zhuǎn)到整個調(diào)用鏈當中能catch到異常的位置處,不能catch的地方就不會執(zhí)行了,所以這可能導致內(nèi)存泄漏、文件流沒關(guān)閉、鎖未釋放**等情況。(free、fclose、unlock未執(zhí)行)
  4. catch(…)可以用來捕獲任意類型對象的異常,一般用于表示"未知異常"或被用作異常的重新拋出時的接收catch塊
  5. 在拋出與捕獲的類型匹配上并不全都是類型相同才能匹配。我們可以使用基類去捕獲 —> 拋出的派生類的對象。 //會在下面具體講解

· 原則2:函數(shù)調(diào)用鏈中的異常 - 棧展開的匹配原則

  1. 查看throw是否在try的內(nèi)部,如果存在能匹配到的catch語句,就跳轉(zhuǎn)到catch中進行異常的處理。
  2. 如果沒有匹配的catch就退出當前棧,去查找調(diào)用鏈當中的能夠匹配到的catch
  3. 如果在main函數(shù)中都沒有找到匹配的catch,則終止程序。

棧展開:上述的這個沿著調(diào)用鏈去逐個棧中查找匹配的catch語句的過程就是棧展開。

image-20211225134740717

//代碼演示:f3()中拋出異常,該異常會被f1()捕捉,而在main函數(shù)中的catch是無法捕捉到的
void f3()
{
	throw 123;
}
void f2()
{
    f3();
}
void f1()
{
    try
    {
        f2();
        cout << "f1() not catched Exception!" << endl;
    }catch(int& err)
    {
        cout << "f1()-err: " << err << endl;
    }
}

int main()
{
    try
    {
        f1();
        cout << "main not catched Exception!" << endl;
    }catch(int& err)
    {
        cout << "main-err: " << err << endl; 
    }
    return 0;
}

image-20211225110321881

注意:

拋出異常對象后,會生成一個異常對象的拷貝(可能是一個臨時對象),這個拷貝的臨時對象在被catch后會被銷毀。異常的執(zhí)行流執(zhí)行順序:從throw拋出異常處跳轉(zhuǎn)到調(diào)用鏈中能夠匹配的catch語句中;然后執(zhí)行catch塊中的代碼;catch執(zhí)行完畢后在當前函數(shù)棧中順序執(zhí)行。(整個調(diào)用鏈中沒有匹配的就終止程序)

2.3 異常的重新拋出

 可能會存在單個catch不能完全處理一個異常的情況,在經(jīng)過一些校正處理后,我們希望將該異常交給外層調(diào)用鏈中的函數(shù)來處理,此時我們可以通過在catch中重新拋出異常的方式把異常傳遞給調(diào)用鏈的上層函數(shù)處理。

//在SecondThrowException()函數(shù)中我們要delete[]動態(tài)開辟(new出來)的空間,
//如果不使用異常的重新拋出的話,就會造成內(nèi)存泄漏問題 (也可以使用RAII)
void FirstThrowException()
{
    throw "First throw a exception!";
}

void SecondThrowException()
{
    int* arr = new int[10];
    try
    {
        FirstThrowException();
    }catch(...)
    {
        cout << "Delete[] arr Success!" << endl;
        delete[] arr;
        throw;
    }
}

void SoluteException()
{
    try
    {
        SecondThrowException();
    }catch(const char* err)
    {
        cout << err << endl;
    }
}

int main()
{
    SoluteException();
    return 0;
}

image-20211225154404777

2.4 自定義異常體系

自定義異常體系實際上就是自己定義的一套異常管理體系,很多公司當中都會自定義自己的異常體系以便于規(guī)范的進行異常管理。它主要用到了我們在上面所說的一條規(guī)則: 我們只需要拋出派生類對象,然后捕獲基類對象就可以了。這樣的拋出與捕獲方式非常便于異常的處理。

class MyException
{
public:
	MyException(string errmsg, int id)
		:_errmsg(errmsg),
		 _id(id)
	{}
	
	virtual string what() const = 0;	//必須放到public下才能讓類外定義的成員訪問到
protected:
	int _id;		//錯誤碼
	string _errmsg;	//存放錯誤信息
	//list<StackInfo> _traceStack;	//存放調(diào)用鏈的信息
    //...
};

class CacheException : public MyException
{
public:
	CacheException(string errmsg, int id)
		:MyException(errmsg, id)
	{}

	virtual string what() const
	{
		return "CacheException!: " + _errmsg;
	}
};

class NetworkException : public MyException
{
public:
	NetworkException(string errmsg, int id)
		:MyException(errmsg, id)
	{}

	virtual string what() const
	{
		return "NetworkException!: " + _errmsg;
	}
};

class SqlException : public MyException
{
public:
	SqlException(string errmsg, int id)
		:MyException(errmsg, id)
	{}

	virtual string what() const
	{
		return "SqlException!: " + _errmsg;
	}
};

int main()
{
	try
	{
		//拋出任意的派生類對象
		throw SqlException("sql open failed", 10);
	}
    catch (const MyException& e)	//只需要捕獲基類對象
	{
		cout << e.what() << endl;	//這里實際上完成了一個多態(tài)
	}
	catch (...)	//走到這里說明出現(xiàn)未知異常
	{
		cout << "Unknown Exception!" << endl;
	}

	return 0;
}

image-20211225153550934

2.5 異常安全

  1. 最好不要在構(gòu)造函數(shù)中拋異常,構(gòu)造函數(shù)是完成對象的構(gòu)造和初始化的,在里面拋異??赡軙е聦ο髽?gòu)造不完整或沒有完全初始化。 (可能會造成內(nèi)存泄漏)
  2. 最好不要在析構(gòu)函數(shù)中拋異常,析構(gòu)函數(shù)是完成資源的清理工作的,在里面拋異??赡軐е沦Y源沒清完就結(jié)束了函數(shù)調(diào)用,從而導致內(nèi)存泄漏、句柄未關(guān)閉等問題。
  3. 注意new、fopen、lock的使用

2.6 異常規(guī)范

異常規(guī)范的指定是為了讓使用者知道函數(shù)可能拋出哪些異常,用法:

void func1() throw(); //表示該函數(shù)不會拋異常
void func2() noexcept; //等價于throw()  表示該函數(shù)不會拋異常
void func3() throw(std::bad_alloc);	//表示該函數(shù)只會拋出bad_alloc的異常
void func4() throw(int, double, string); //表示該函數(shù)會拋出int/double/string類型中的某種異常

2.7 C++標準庫的異常體系

C++提供了一系列標準的異常,定義在中,下面是這些異常的組織形式。

異常描述
std::exception該異常是所有標準 C++ 異常的父類。
std::bad_alloc該異??梢酝ㄟ^ new 拋出。
std::bad_cast該異??梢酝ㄟ^ dynamic_cast 拋出。
std::bad_exception這在處理 C++ 程序中無法預期的異常時非常有用。
std::bad_typeid該異??梢酝ㄟ^ typeid 拋出。
std::logic_error理論上可以通過讀取代碼來檢測到的異常。
std::domain_error當使用了一個無效的數(shù)學域時,會拋出該異常。
std::invalid_argument當使用了無效的參數(shù)時,會拋出該異常。
std::length_error當創(chuàng)建了太長的 std::string 時,會拋出該異常。
std::out_of_range該異??梢酝ㄟ^方法拋出,例如 std::vector 和 std::bitset<>::operator。
std::runtime_error理論上不可以通過讀取代碼來檢測到的異常。
std::overflow_error當發(fā)生數(shù)學上溢時,會拋出該異常。
std::range_error當嘗試存儲超出范圍的值時,會拋出該異常。
std::underflow_error當發(fā)生數(shù)學下溢時,會拋出該異常。
int main()
{
	try
    {
        vector<int> v(5);
        v.at(5) = 0;	//v.at(下標) = v[下標] + 拋異常
    }
    catch(const exception& e)
    {
        cout << e.what() << endl;
    }
    catch(...)
    {
		cout << "Unknown Exception!" << endl;        
    }
}

2.8 異常的優(yōu)缺點

2.8.1 優(yōu)點

  1. 清晰的顯示出錯誤信息
  2. 可以很好地解決返回值需要返回有效數(shù)據(jù)的函數(shù) //如T& operator[ ] (int index)
  3. 在多層函數(shù)調(diào)用時發(fā)生錯誤,可以用直接在外層進行捕獲異常
  4. 異常在很多第三方庫中也有使用 //boost、gtest、gmock

2.8.2 缺點

  1. 異常會導致執(zhí)行流跳轉(zhuǎn),這會使得調(diào)試分析程序時更加困難
  2. C++沒有GC (垃圾回收機制),使用異常時可能導致資源泄露等異常安全問題。
  3. C++標準庫的異常體系不實用
  4. C++的允許拋出任意類型的異常,在項目中不進行規(guī)范管理的話,會十分混亂。 //一般需要定義一套繼承體系的異常規(guī)范

總結(jié)

到此這篇關(guān)于C++異常的文章就介紹到這了,更多相關(guān)C++異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • windows下vscode環(huán)境c++利用matplotlibcpp繪圖

    windows下vscode環(huán)境c++利用matplotlibcpp繪圖

    本文主要介紹了windows下vscode環(huán)境c++利用matplotlibcpp繪圖,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02
  • C++中的異常實例詳解

    C++中的異常實例詳解

    異常處理是C++的一項語言機制,用于在程序中處理異常事件,下面這篇文章主要給大家介紹了關(guān)于C++中異常的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • C語言編程實例之輸出指定圖形問題

    C語言編程實例之輸出指定圖形問題

    這篇文章主要介紹了C語言編程實例之輸出指定圖形問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • C++之eigen安裝與測試方式

    C++之eigen安裝與測試方式

    這篇文章主要介紹了C++之eigen安裝與測試方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • C++中友元函數(shù)(friend)解析

    C++中友元函數(shù)(friend)解析

    這篇文章主要分享了C++友元函數(shù)講解,C++提供了一種形式的訪問權(quán)限,叫做友元,友元有三種,分別是友元函數(shù)、友元類和友元成員函數(shù),下面將詳細介紹該內(nèi)容,需要的小伙伴可以參考一下
    2022-01-01
  • c語言算術(shù)運算符越界問題解決方案

    c語言算術(shù)運算符越界問題解決方案

    大量的安全漏洞是由于計算機算術(shù)運算的微妙細節(jié)引起的, 具體的C語言, 諸如符號數(shù)和無符號數(shù)之間轉(zhuǎn)換, 算術(shù)運算的越界都會導致不可預知的錯誤和安全漏洞, 具體的案例數(shù)不勝數(shù).
    2012-11-11
  • c++語言中虛函數(shù)實現(xiàn)多態(tài)的原理詳解

    c++語言中虛函數(shù)實現(xiàn)多態(tài)的原理詳解

    這篇文章主要給大家介紹了關(guān)于c++語言中虛函數(shù)實現(xiàn)多態(tài)的原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用c++語言具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-05-05
  • C語言實現(xiàn)通訊錄功能的流程與代碼

    C語言實現(xiàn)通訊錄功能的流程與代碼

    通訊錄是一個可以記錄親人、好友信息的工具,這篇文章主要為大家詳細介紹了C語言實現(xiàn)通訊錄管理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C語言工程文件該如何寫(以三子棋游戲為例)

    C語言工程文件該如何寫(以三子棋游戲為例)

    工程上寫代碼應分為多個文件,那么你知道C語言工程文件該如何寫嗎,本文就以以三子棋游戲為例,介紹一下,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • MFC控件之CListCtrl的應用實例教程

    MFC控件之CListCtrl的應用實例教程

    這篇文章主要介紹了MFC控件中CListCtrl的應用方法,包括了針對表格的一些操作,是MFC中比較重要的一個控件類,需要的朋友可以參考下
    2014-08-08

最新評論