最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

1. 異常

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

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

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

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

  • 使用錯(cuò)誤碼時(shí),還需要查看錯(cuò)誤碼表,去找每個(gè)錯(cuò)誤碼的含義
  • 當(dāng)一個(gè)函數(shù)是通過(guò)返回值去輸出數(shù)據(jù),那么發(fā)生錯(cuò)誤的時(shí)候很難處理 (不好區(qū)設(shè)置發(fā)生錯(cuò)誤時(shí)返回什么)
  • 如果調(diào)用的函數(shù)棧很深時(shí),使用錯(cuò)誤碼去一層層返回時(shí),處理起來(lái)很麻煩
//第2點(diǎn)
T& operator[](int index)
{
	//問(wèn)題: 當(dāng)訪問(wèn)的下標(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. 異常是通過(guò)拋出對(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)存泄漏、文件流沒(méi)關(guān)閉、鎖未釋放**等情況。(free、fclose、unlock未執(zhí)行)
  4. catch(…)可以用來(lái)捕獲任意類型對(duì)象的異常,一般用于表示"未知異常"或被用作異常的重新拋出時(shí)的接收catch塊
  5. 在拋出與捕獲的類型匹配上并不全都是類型相同才能匹配。我們可以使用基類去捕獲 —> 拋出的派生類的對(duì)象。 //會(huì)在下面具體講解

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

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

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

image-20211225134740717

//代碼演示:f3()中拋出異常,該異常會(huì)被f1()捕捉,而在main函數(shù)中的catch是無(wú)法捕捉到的
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語(yǔ)句中;然后執(zhí)行catch塊中的代碼;catch執(zhí)行完畢后在當(dāng)前函數(shù)棧中順序執(zhí)行。(整個(gè)調(diào)用鏈中沒(méi)有匹配的就終止程序)

2.3 異常的重新拋出

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

//在SecondThrowException()函數(shù)中我們要delete[]動(dòng)態(tài)開(kāi)辟(new出來(lái))的空間,
//如果不使用異常的重新拋出的話,就會(huì)造成內(nèi)存泄漏問(wèn)題 (也可以使用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(shuō)的一條規(guī)則: 我們只需要拋出派生類對(duì)象,然后捕獲基類對(duì)象就可以了。這樣的拋出與捕獲方式非常便于異常的處理。

class MyException
{
public:
	MyException(string errmsg, int id)
		:_errmsg(errmsg),
		 _id(id)
	{}
	
	virtual string what() const = 0;	//必須放到public下才能讓類外定義的成員訪問(wèn)到
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 (...)	//走到這里說(shuō)明出現(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)造不完整或沒(méi)有完全初始化。 (可能會(huì)造成內(nèi)存泄漏)
  2. 最好不要在析構(gòu)函數(shù)中拋異常,析構(gòu)函數(shù)是完成資源的清理工作的,在里面拋異??赡軐?dǎo)致資源沒(méi)清完就結(jié)束了函數(shù)調(diào)用,從而導(dǎo)致內(nèi)存泄漏、句柄未關(guān)閉等問(wè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)庫(kù)的異常體系

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

異常描述
std::exception該異常是所有標(biāo)準(zhǔn) C++ 異常的父類。
std::bad_alloc該異??梢酝ㄟ^(guò) new 拋出。
std::bad_cast該異??梢酝ㄟ^(guò) dynamic_cast 拋出。
std::bad_exception這在處理 C++ 程序中無(wú)法預(yù)期的異常時(shí)非常有用。
std::bad_typeid該異常可以通過(guò) typeid 拋出。
std::logic_error理論上可以通過(guò)讀取代碼來(lái)檢測(cè)到的異常。
std::domain_error當(dāng)使用了一個(gè)無(wú)效的數(shù)學(xué)域時(shí),會(huì)拋出該異常。
std::invalid_argument當(dāng)使用了無(wú)效的參數(shù)時(shí),會(huì)拋出該異常。
std::length_error當(dāng)創(chuàng)建了太長(zhǎng)的 std::string 時(shí),會(huì)拋出該異常。
std::out_of_range該異??梢酝ㄟ^(guò)方法拋出,例如 std::vector 和 std::bitset<>::operator。
std::runtime_error理論上不可以通過(guò)讀取代碼來(lái)檢測(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. 異常在很多第三方庫(kù)中也有使用 //boost、gtest、gmock

2.8.2 缺點(diǎn)

  1. 異常會(huì)導(dǎo)致執(zhí)行流跳轉(zhuǎn),這會(huì)使得調(diào)試分析程序時(shí)更加困難
  2. C++沒(méi)有GC (垃圾回收機(jī)制),使用異常時(shí)可能導(dǎo)致資源泄露等異常安全問(wèn)題。
  3. C++標(biāo)準(zhǔn)庫(kù)的異常體系不實(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)文章

  • Qt實(shí)現(xiàn)一個(gè)簡(jiǎn)單的word文檔編輯器

    Qt實(shí)現(xiàn)一個(gè)簡(jiǎn)單的word文檔編輯器

    本文主要介紹了Qt實(shí)現(xiàn)一個(gè)簡(jiǎn)單的word文檔編輯器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • C++靜態(tài)持續(xù)變量介紹

    C++靜態(tài)持續(xù)變量介紹

    這篇文章主要介紹了 C++靜態(tài)持續(xù)變量,靜態(tài)持續(xù)變量的定義C++和C語(yǔ)言是一樣的,它擁有三種鏈接性,即外部鏈接性、內(nèi)部連接性和無(wú)鏈接性。其中外部鏈接性指的是可以在其他文件中訪問(wèn),內(nèi)部鏈接性指的是只能在當(dāng)前文件訪問(wèn),需要的朋友可以參考一下
    2021-11-11
  • C/C++ 中const關(guān)鍵字的用法小結(jié)

    C/C++ 中const關(guān)鍵字的用法小結(jié)

    C++中的const關(guān)鍵字的用法非常靈活,而使用const將大大改善程序的健壯性。這篇文章主要介紹了C/C++ 中const關(guān)鍵字的用法,需要的朋友可以參考下
    2020-02-02
  • 詳解OpenMP的線程同步機(jī)制

    詳解OpenMP的線程同步機(jī)制

    在本篇文章當(dāng)中主要給大家介紹?OpenMP?當(dāng)中線程的同步和互斥機(jī)制,在?OpenMP?當(dāng)中主要有三種不同的線程之間的互斥方式。下面就來(lái)和大家來(lái)討論一下OpenMP當(dāng)中的互斥操作,需要的可以參考一下
    2023-01-01
  • C++的內(nèi)聯(lián)函數(shù)你了解嗎

    C++的內(nèi)聯(lián)函數(shù)你了解嗎

    這篇文章主要為大家詳細(xì)介紹了C++的內(nèi)聯(lián)函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • 基于MFC實(shí)現(xiàn)自定義復(fù)選框效果

    基于MFC實(shí)現(xiàn)自定義復(fù)選框效果

    復(fù)選框是一種可同時(shí)選中多項(xiàng)的基礎(chǔ)控件,主要是有兩種明顯的狀態(tài):選中與非選中。本文將通過(guò)MFC框架實(shí)現(xiàn)自定義復(fù)選框效果,感興趣的可以了解一下
    2022-02-02
  • C++中求組合數(shù)的各種方法總結(jié)詳解

    C++中求組合數(shù)的各種方法總結(jié)詳解

    本篇文章是對(duì)C++中的求組合數(shù)的各種方法進(jìn)行了詳細(xì)的介紹。需要的朋友參考下
    2013-05-05
  • 使用C語(yǔ)言順序表數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)棧的代碼示例

    使用C語(yǔ)言順序表數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)棧的代碼示例

    這篇文章主要給大家介紹了如何使用C語(yǔ)言順序表數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)棧,文章通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下
    2023-09-09
  • VCPKG安裝和使用教程(經(jīng)驗(yàn)總結(jié))

    VCPKG安裝和使用教程(經(jīng)驗(yàn)總結(jié))

    這篇文章主要介紹了VCPKG安裝和使用教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • C++實(shí)現(xiàn)將輸入的內(nèi)容輸出到文本文件

    C++實(shí)現(xiàn)將輸入的內(nèi)容輸出到文本文件

    這篇文章主要介紹了C++實(shí)現(xiàn)將輸入的內(nèi)容輸出到文本文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08

最新評(píng)論

文水县| 上思县| 汶川县| 咸宁市| 甘肃省| 霸州市| 枣强县| 富顺县| 昭平县| 彩票| 随州市| 武清区| 布尔津县| 江北区| 江门市| 海盐县| 德保县| 广灵县| 剑阁县| 涿州市| 昌乐县| 邵武市| 泗水县| 江北区| 凤凰县| 九台市| 南皮县| 新乡市| 綦江县| 通榆县| 成安县| 渭南市| 凉山| 长治市| 子洲县| 志丹县| 基隆市| 高尔夫| 阿合奇县| 云梦县| 喀喇|