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

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ū)設(shè)置發(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ā)的,該對象的類型決定了應(yīng)該匹配到哪個catch塊
  2. 異常的拋出會去匹配在整個調(diào)用鏈中與該對象類型相匹配且距離最近的那個
  3. 當異常拋出后,執(zhí)行流會直接跳轉(zhuǎn)到整個調(diào)用鏈當中能catch到異常的位置處,不能catch的地方就不會執(zhí)行了,所以這可能導(dǎo)致內(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)造和初始化的,在里面拋異??赡軙?dǎo)致對象構(gòu)造不完整或沒有完全初始化。 (可能會造成內(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ù)不會拋異常
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++ 程序中無法預(yù)期的異常時非常有用。
std::bad_typeid該異??梢酝ㄟ^ typeid 拋出。
std::logic_error理論上可以通過讀取代碼來檢測到的異常。
std::domain_error當使用了一個無效的數(shù)學(xué)域時,會拋出該異常。
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ù)學(xué)上溢時,會拋出該異常。
std::range_error當嘗試存儲超出范圍的值時,會拋出該異常。
std::underflow_error當發(fā)生數(shù)學(xué)下溢時,會拋出該異常。
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. 異常會導(dǎo)致執(zhí)行流跳轉(zhuǎn),這會使得調(diào)試分析程序時更加困難
  2. C++沒有GC (垃圾回收機制),使用異常時可能導(dǎo)致資源泄露等異常安全問題。
  3. C++標準庫的異常體系不實用
  4. C++的允許拋出任意類型的異常,在項目中不進行規(guī)范管理的話,會十分混亂。 //一般需要定義一套繼承體系的異常規(guī)范

總結(jié)

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

相關(guān)文章

  • Qt實現(xiàn)一個簡單的word文檔編輯器

    Qt實現(xiàn)一個簡單的word文檔編輯器

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

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

    這篇文章主要介紹了 C++靜態(tài)持續(xù)變量,靜態(tài)持續(xù)變量的定義C++和C語言是一樣的,它擁有三種鏈接性,即外部鏈接性、內(nèi)部連接性和無鏈接性。其中外部鏈接性指的是可以在其他文件中訪問,內(nèi)部鏈接性指的是只能在當前文件訪問,需要的朋友可以參考一下
    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的線程同步機制

    詳解OpenMP的線程同步機制

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評論

东宁县| 乡城县| 亚东县| 南华县| 叙永县| 阿尔山市| 通化县| 禄丰县| 眉山市| 永登县| 朔州市| 郴州市| 靖远县| 太仆寺旗| 锡林浩特市| 香格里拉县| 礼泉县| 百色市| 留坝县| 北海市| 山阳县| 广宁县| 和林格尔县| 河北省| 太仓市| 会宁县| 宁陵县| 邓州市| 翁源县| 西林县| 宁晋县| 玛纳斯县| 灵丘县| 孟村| 台中县| 吴忠市| 壤塘县| 凉城县| 财经| 措勤县| 井陉县|