亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++中的異常實(shí)例詳解

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

1. 異常

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

1.1 C語言中處理錯(cuò)誤的方式

  • 返回錯(cuò)誤碼 (很多API接口都會(huì)把錯(cuò)誤碼放到errno當(dāng)中)
  • 終止程序 (assert終止、除零錯(cuò)誤、段錯(cuò)誤) [產(chǎn)生信號(hào)去終止進(jìn)程]
  • C標(biāo)準(zhǔn)庫中setjump和longjump組合

1.2 C語言處理錯(cuò)誤方式的缺陷

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

2. C++異常

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

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

2.2 異常的使用

2.2.1 異常的拋出和匹配原則

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

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

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

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

image-20211225134740717

//代碼演示:f3()中拋出異常,該異常會(huì)被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

注意:

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

2.3 異常的重新拋出

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

//在SecondThrowException()函數(shù)中我們要delete[]動(dòng)態(tài)開辟(new出來)的空間,
//如果不使用異常的重新拋出的話,就會(huì)造成內(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 自定義異常體系

自定義異常體系實(shí)際上就是自己定義的一套異常管理體系,很多公司當(dāng)中都會(huì)自定義自己的異常體系以便于規(guī)范的進(jìn)行異常管理。它主要用到了我們?cè)谏厦嫠f的一條規(guī)則: 我們只需要拋出派生類對(duì)象,然后捕獲基類對(duì)象就可以了。這樣的拋出與捕獲方式非常便于異常的處理。

class MyException
{
public:
	MyException(string errmsg, int id)
		:_errmsg(errmsg),
		 _id(id)
	{}
	
	virtual string what() const = 0;	//必須放到public下才能讓類外定義的成員訪問到
protected:
	int _id;		//錯(cuò)誤碼
	string _errmsg;	//存放錯(cuò)誤信息
	//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
	{
		//拋出任意的派生類對(duì)象
		throw SqlException("sql open failed", 10);
	}
    catch (const MyException& e)	//只需要捕獲基類對(duì)象
	{
		cout << e.what() << endl;	//這里實(shí)際上完成了一個(gè)多態(tài)
	}
	catch (...)	//走到這里說明出現(xiàn)未知異常
	{
		cout << "Unknown Exception!" << endl;
	}

	return 0;
}

image-20211225153550934

2.5 異常安全

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

2.6 異常規(guī)范

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

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

2.7 C++標(biāo)準(zhǔn)庫的異常體系

C++提供了一系列標(biāo)準(zhǔn)的異常,定義在中,下面是這些異常的組織形式。

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

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

2.8.1 優(yōu)點(diǎn)

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

2.8.2 缺點(diǎn)

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

總結(jié)

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

相關(guān)文章

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

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

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

    C++中的異常實(shí)例詳解

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

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

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

    C++之eigen安裝與測(cè)試方式

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

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

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

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

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

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

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

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

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

    C語言工程文件該如何寫(以三子棋游戲?yàn)槔?

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

    MFC控件之CListCtrl的應(yīng)用實(shí)例教程

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

最新評(píng)論