青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

山寨:不是最好的,是最適合我們的!歡迎體驗山寨 中文版MSDN

Blog @ Blog

當華美的葉片落盡,生命的脈絡(luò)才歷歷可見。 -- 聶魯達

常用鏈接

統(tǒng)計

積分與排名

BBS

Blog

Web

最新評論

C++中的錯誤處理

轉(zhuǎn)自:http://www.frontfree.net/view/article_755.html

原創(chuàng):monkeyfu

處理在程序的運行時刻發(fā)生的錯誤,對于任何一個程序設(shè)計者來講都是不陌生的。對于錯誤的處理,我們有很多方法,本篇著重介紹的是C++中的錯誤異常處理。

在介紹C++中的錯誤異常處理之前,我們先來看一下常用的錯誤處理方式。

1.返回值 可以說這是最常用的錯誤處理方式之一,但其存在著一個致命的問題。就是返回值的檢查與否是由調(diào)用者主動控制的。如果調(diào)用者不檢查返回值,那也沒有任何 機制能夠強迫他這么做。再一個,考慮在C++中參數(shù)表相同而返回值不同的重載情況。在這種情況下,如果調(diào)用者不檢查返回值的話,編譯器根本不清楚應(yīng)該調(diào)用哪個函數(shù)。
2.全局狀態(tài)標示符 這種辦法同返回值一樣,也是需要調(diào)用者主動檢查的。并且由于其是全局的,因此在多線程程序中,還必須保證它的線程安全性,必須要讓檢查者知道這是誰的返回值。
3.setjmp()/longjmp() 你完全可以將longjmp()當成遠程的goto語句進行調(diào)用(goto語句只能左右于本地函數(shù)里)。但這個函數(shù)卻存在著很大甚至是致命的危險。暫且放下該函數(shù)會破壞結(jié)構(gòu)化程序設(shè)計風格不說。其一,longjmp()只能處理int型的異常。其二,也就是最致命的一點就是,longjmp()不會調(diào)用析構(gòu)函數(shù),而C++的 異常處理機制卻會完成這個事情。因此,在C++中,千萬不要使用setjmp()longjmp()函數(shù)。
4.斷言 對于斷言(Assert),其僅僅是在Debug版本中起作用,在Release中其是不存在的。另外斷言與我們通常所說的錯誤處理方式不同,他是用來處理我們可能會發(fā)生這個錯誤,并能夠避免的這種情況。

在介紹過上面那些存在問題的錯誤處理方式后,現(xiàn)在讓我們來看看C++中的異常機制是如何處理錯誤的。首先說,C++的異常處理不會像上面提到的那些方法一樣,必須是調(diào)用著主動檢查。因為在C++中,一旦拋出(throw)一個異常,而程序不捕獲(catch)的話,那么最終的結(jié)果就是abort()函數(shù)被調(diào)用,使得程序被終止。

下面我們來看一下C++異常處理(以下稱EH)的基本語法和語意。
其引入了3個關(guān)鍵字,分別是:

catch
, throw, try

throw

異常由throw拋出,其格式為

throw [expression]

函數(shù)在定義時通過異常規(guī)格申明定義其會拋出什么類型的異常,其格式為:

throw([type-ID-list])

type-ID-list是一個可選項,其中包括了一個或多個類型的名字,它們之間以逗號分隔。

例如:

void func() throw(int, some_class_type)

則表明會拋出intsome_class_type類型異常。

對于一個空的異常規(guī)格申明,表示不拋出任何異常。
如:

void func() throw(...)

而如果函數(shù)沒有異常規(guī)格申明,則表示會拋出任何類型的異常。
不過這里存在一種情況,例如:

void func() throw(int) //指明拋出int型異常
{
...
subfunc(); //但可能從這里拋出非int型異常
...
}

try -- catch

try塊中的異常處理函數(shù)對異常進行捕獲。其可以包含一個或多個處理函數(shù),其形式如下:

catch (exception-declaration) compound-statement

處理函數(shù)的異常申明指明了其要捕獲什么類型的異常。
對于異常申明其可以是無名的,例如:catch(char *),其表明會捕獲一個char *類型異常,但由于是無名的,因此不能對其進行操作。另外異常申明也可以存在如下形式:catch(...),其表明會捕獲任何類型的異常。

舉例:

void func() throw(int, some_class_type)
{
    int i;
    ........
    throw i;
    ........
}

int main()
{
    try
   
{
        func();
    }
    catch(int e)
    {
        //處理int型異常
   
}
    catch(some_class_type)
    {
        //處理some_class_type型異常
   
}
    .......
    return 0;
}

從上面的例子可以看出,當函數(shù)拋出異常時,throw后面要帶一個拋出的對象。但這并不是必須的,例如:

catch(int e)
{
    .......
    throw;
}

throw后面沒有接任何對象,這表明throw會再次拋出已存在的異常對象,因此其必須位于catch塊中。

下面介紹一些C++提供的標準異常

namespace std
{
//exception派生
class logic_error; //邏輯錯誤,在程序運行前可以檢測出來

//logic_error派生
class domain_error; //違反了前置條件
class invalid_argument; //指出函數(shù)的一個無效參數(shù)
class length_error; //指出有一個超過類型size_t的最大可表現(xiàn)值長度的對象的企圖
class out_of_range; //參數(shù)越界
class bad_cast; //在運行時類型識別中有一個無效的dynamic_cast表達式
class bad_typeid; //報告在表達試typeid(*p)中有一個空指針p

//exception派生
class runtime_error; //運行時錯誤,僅在程序運行中檢測到

//runtime_error派生
class range_error; //違反后置條件
class overflow_error; //報告一個算術(shù)溢出
class bad_alloc; //存儲分配錯誤
}

在C++標準庫頭文件<exception>申明了幾個EH類型和函數(shù),它們是:

namespace std
{
//EH類型
class bad_exception;
class exception;

typedef void (*terminate_handler)();
typedef void (*unexpected_handler)();

// 函數(shù)
terminate_handler set_terminate(terminate_handler) throw();
unexpected_handler set_unexpected(unexpected_handler) throw();

void terminate();
void unexpected();

bool uncaught_exception();
}


exception 是所有標準庫拋出的異常的基類。
uncaught_exception() 函數(shù)在異常被拋出卻沒有被捕獲時返回true,其它情況返回false
terminate() 在異常處理陷入了不可恢復狀態(tài),如:重入時被調(diào)用。
unexpected() 在函數(shù)拋出一個沒有在“異常規(guī)格申明”中申明的異常時被調(diào)用。

運行庫提供了缺省terminate_handler()unexpected_handler()函數(shù)處理對應(yīng)的情況。你可以通過set_terminate()set_unexpected()函數(shù)替換庫的默認版本。這兩個函數(shù),其可以獲取不帶輸入輸出參數(shù)的函數(shù),并且該函數(shù)會返回原terminate或者unexpected函數(shù)的地址指針。以便在使用中調(diào)用或者以后的恢復。另外,在terminate ()中。其必須不返回或者拋出異常。

在介紹了EH的基本知識后讓我們來看看EH是如何工作的。

一般來說當發(fā)生函數(shù)調(diào)用的時候,都會進行諸如,保存寄存器值,參數(shù)壓棧,創(chuàng)建被調(diào)函數(shù)堆棧等保護現(xiàn)場的工作,而在函數(shù)返回的時候則會進行與此相反的恢復現(xiàn)場的工作。

這樣,當一個異常發(fā)生時,程序會在異常點處停止,然后開始搜索異常處理函數(shù),其過程同函數(shù)返回相同,延調(diào)用棧向上搜索,直到找到一個與異常對象類型像匹配的異常申明,并進行相應(yīng)的異常處理函數(shù),在異常處理結(jié)束后,程序跳到異常處理函數(shù)所在try快最接近的下面一條語句開始執(zhí)行。如果沒有找到合適的異常申明,則最終會調(diào)用std :: unexpected(),并在其中調(diào)用std:terminate()直到abort(),程序被終止。

這也就意味著C++對于異常處理的模式始終是終止的。

例如:

#include <iostream.h>
static void func(int n)
{
  if (n)
  throw 100;
}

extern int main()
{
  try
{
func(1);
cout<<"程序不會執(zhí)行到這里"<<endl;
}
catch(int)
{
cout<<"捕獲一個int型異常"<<endl;
}
catch(...)
{
cout<<"捕獲任意類型異常"<<endl;
}

  cout<<"繼續(xù)執(zhí)行"<<endl;

return 0;
}

該程序在運行時會打印如下信息:

捕獲一個int型異常
捕獲任意類型異常


至于異常處理的另一種模式恢復模式??梢酝ㄟ^循環(huán)檢測直到結(jié)果滿意為止。但在實際中,往往產(chǎn)生異常的地方與異常處理函數(shù)距離可能會比較遠,在這種情況下恢復模式就不那么可行了。

雖然,在異常處理延調(diào)用棧向上走的過程中回析構(gòu)所有棧上的對象,但其并不會對堆中的對象進行處理,這樣將會引起嚴重的資源泄露問題。

例如:

void func()
{
    testclass *p = new testclass();
    ...
    test(p); //這里會拋出異常
   
...
    delete p; //在拋出異常后,這里不會被執(zhí)行,因此會導致內(nèi)存泄露問題。
}

為了解決這個問題,C++提供了std::auto_ptr模板。其原理就是,將指針用一個棧上的模版實例保護起來,當發(fā)生異常的時候,模版會被析構(gòu),在析構(gòu)函數(shù)中指針也就被delete了。

例如:

void func()
{
    std::auto_ptr<testclass> p(new testclass());
    ...
    test(p.get());
    ...
}

另外,在構(gòu)造函數(shù)中拋出異常并不會引發(fā)析構(gòu)函數(shù)。這一點要十分注意。因為這也會產(chǎn)生資源泄露問題。

例如:

class test
{
public:
test() { c = new char[10]; throw -1;}
~test() {delete c;}

  private:
char *c;
};

void proc()
{
try{
test t;
}
catch(int)
{
.......
}
}


由于異常是在test的構(gòu)造函數(shù)中產(chǎn)生的,因此其不會引發(fā)其析構(gòu)函數(shù)的調(diào)用。于是就如程序所示,產(chǎn)生了內(nèi)存泄露問題。對于這種問題,最好的解決辦法還是使用auto_ptr

對于析構(gòu)函數(shù),則不要在其中拋出異常。其原因在于析構(gòu)函數(shù)會在其他異常拋出時被調(diào)用,這樣就會引發(fā)異常的重入問題,進而導致terminate()被調(diào)用。如果在析構(gòu)函數(shù)中真要拋出異常,如:析構(gòu)函數(shù)調(diào)用的函數(shù)會拋出異常等,則必須在該析構(gòu)函數(shù)內(nèi)將其捕獲。

前面說到要“找到一個與異常對象類型像匹配的異常申明”。事實上,這種匹配并不要求的十分準確。
考慮如下例子:

#include <iostream.h>

class base
{
public:
virtual void what()
{
cout << "base" << endl;
}
};

class derived: public base
{
public:
void what()
{
cout << "derived" << endl;
}
};

void f()
{
throw derived();
}

main()
{
try
{
f();
}
catch(base b)
{
b.what();
}

   try
{
f();
}
catch(base& b)
{
b.what();
}
}

其顯示結(jié)果為:

base
derived


為什么會這樣呢。因為如果異常拋出一個派生類對象,而恰好又其基類所捕獲到。那么該對象會被做"切片"處理。也就是說相對于基類,派生元素會被割下。在例子中derived的vptr會被設(shè)為base的virtual table。因此虛函數(shù)what就會呈現(xiàn)出這種行為。而當通過引用捕獲時,得到的僅僅是其地址,對象不會被做切片處理。vptr因此也就不會發(fā)生變化,所以what仍然呈現(xiàn)出來derived的行為。

因此,這也就提醒我們將基類處理放在最后,在實際中更有意義。因為這樣可以盡可能的在前面的處理中保存信息。

posted on 2008-01-26 11:31 isabc 閱讀(645) 評論(0)  編輯 收藏 引用 所屬分類: C++基礎(chǔ)

廣告信息(免費廣告聯(lián)系)

中文版MSDN:
歡迎體驗

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            日韩一二三区视频| 亚洲国产欧美一区二区三区同亚洲 | 久久成年人视频| 女主播福利一区| 久久精品女人| 久久av老司机精品网站导航| 午夜视频久久久久久| 亚洲欧美精品在线观看| 亚洲欧美一区二区原创| 午夜日韩福利| 久久天天躁狠狠躁夜夜av| 久久天天狠狠| 亚洲国产精品欧美一二99| 亚洲国产网站| 日韩性生活视频| 亚洲四色影视在线观看| 性欧美大战久久久久久久免费观看 | 亚洲视频一区二区免费在线观看| 精品福利免费观看| 激情综合色丁香一区二区| 亚洲成色777777女色窝| 9国产精品视频| 亚洲男同1069视频| 欧美在线91| 欧美激情中文字幕在线| 在线综合亚洲欧美在线视频| 欧美一区二区三区成人| 欧美成人中文字幕| 国产精品伦一区| 1769国内精品视频在线播放| 亚洲视频网站在线观看| 欧美伊人久久大香线蕉综合69| 麻豆91精品91久久久的内涵| 亚洲美女在线视频| 久久精品在这里| 欧美日韩精品中文字幕| 国产亚洲aⅴaaaaaa毛片| 亚洲日本中文字幕| 欧美在线日韩| 亚洲美女黄网| 久久久免费精品| 国产精品入口尤物| 日韩午夜电影| 欧美阿v一级看视频| 亚洲男人的天堂在线aⅴ视频| 欧美www在线| 国产亚洲精品美女| 亚洲性图久久| 欧美黄网免费在线观看| 午夜日韩在线| 欧美三级第一页| 亚洲精品欧美日韩| 欧美jizzhd精品欧美巨大免费| 亚洲视频在线观看视频| 欧美日韩国产三区| 亚洲精品乱码久久久久久日本蜜臀| 午夜精品久久久久久久久久久久 | 亚洲国产另类久久精品| 欧美在线网站| 国产毛片精品国产一区二区三区| 一区二区三区产品免费精品久久75| 理论片一区二区在线| 午夜视频久久久久久| 国产精品免费福利| 亚洲综合不卡| 一区二区欧美精品| 欧美日韩亚洲91| 一区二区免费在线视频| 亚洲激情av| 欧美顶级艳妇交换群宴| 久久精品欧美日韩| 国产亚洲永久域名| 久久精品三级| 亚洲已满18点击进入久久| 欧美色另类天堂2015| 中文在线不卡| 亚洲视频在线观看免费| 国产精品无码永久免费888| 亚洲欧美国产制服动漫| 中文亚洲免费| 国产农村妇女毛片精品久久麻豆 | 在线观看精品一区| 久久亚洲春色中文字幕| 久久精品网址| 欧美午夜久久| 亚洲女ⅴideoshd黑人| 亚洲一区二区三区中文字幕 | 欧美日韩一区二区免费在线观看 | 国产欧美日韩另类一区| 久久精品国内一区二区三区| 久久久精品五月天| 91久久极品少妇xxxxⅹ软件| 亚洲国产清纯| 国产老女人精品毛片久久| 久久综合久久久| 欧美伦理在线观看| 欧美一区二区三区视频| 久久久蜜臀国产一区二区| 亚洲人成艺术| 9人人澡人人爽人人精品| 国产欧美一区视频| 亚洲福利免费| 国产精品高潮粉嫩av| 久久久精品动漫| 欧美激情二区三区| 久久精品盗摄| 欧美日在线观看| 另类亚洲自拍| 欧美三级午夜理伦三级中文幕| 久久精品中文字幕一区| 欧美 日韩 国产精品免费观看| 亚洲伊人伊色伊影伊综合网| 久久久久久久999精品视频| 一区二区三区四区五区精品| 欧美亚洲综合在线| 亚洲天堂av在线免费观看| 久久成人免费视频| 亚洲图色在线| 欧美a级片网| 久久夜色精品亚洲噜噜国产mv | 亚洲女同性videos| 亚洲精品日本| 久久综合久久综合久久综合| 亚洲在线黄色| 国产一区99| 欧美激情亚洲综合一区| 国产婷婷色综合av蜜臀av| 亚洲美女黄色片| 亚洲精品乱码久久久久久按摩观 | 欧美尤物一区| 亚洲女同精品视频| 欧美久久影院| 欧美激情91| 亚洲国产精品123| 久久精品国产亚洲高清剧情介绍| 亚洲男同1069视频| 国产精品久久久久久久午夜| 亚洲免费av观看| 一区二区三区www| 欧美日韩另类在线| 99精品欧美一区| 亚洲欧美福利一区二区| 国产精品第一页第二页第三页| 91久久一区二区| 亚洲激情二区| 美国成人直播| 黄色成人在线免费| 亚洲综合视频一区| 午夜精品影院在线观看| 欧美日本高清| 99re热这里只有精品免费视频| 久久综合色婷婷| 久久久久久久综合日本| 国产精品都在这里| 亚洲精选大片| 欧美伊人久久| 国产欧美精品xxxx另类| 亚洲免费一区二区| 午夜欧美不卡精品aaaaa| 国产一区欧美| 久久精品国产欧美激情| 久久爱www久久做| 国产精品丝袜白浆摸在线| 久久夜色精品亚洲噜噜国产mv| 国产老女人精品毛片久久| 亚洲一区二区三区精品动漫| 欧美一级在线视频| 国产精品香蕉在线观看| 久久五月激情| 亚洲国产欧美精品| 欧美日韩国产片| 欧美福利电影在线观看| 一区二区成人精品| 欧美精品二区| 亚洲精选视频免费看| 欧美一区二区视频在线观看2020 | 亚洲欧美日韩电影| 国产精品chinese| 久久精品亚洲热| 欧美大片免费| 99亚洲一区二区| 久久天堂av综合合色| 中文国产一区| 久久国产乱子精品免费女 | 国产精品极品美女粉嫩高清在线 | 日韩香蕉视频| 亚洲国产精品久久久久婷婷884 | 亚洲视频第一页| 亚洲一区三区电影在线观看| 狼狼综合久久久久综合网| 久久久久一区二区| 影音先锋久久资源网| 欧美亚州一区二区三区| 亚洲综合色噜噜狠狠| 久久午夜精品| 亚洲精品久久久久久下一站| 欧美一区亚洲| 亚洲网站在线| 久久综合九九| 中文在线不卡|