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

Design&Art

C++博客 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
  26 Posts :: 0 Stories :: 38 Comments :: 0 Trackbacks
c++中的錯(cuò)誤處理
原創(chuàng):monkeyfu 2003年6月19日

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

在介紹C++中的錯(cuò)誤異常處理之前,我們先來(lái)看一下常用的錯(cuò)誤處理方式。

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

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

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

catch
, throw, try

throw

異常由throw拋出,其格式為

throw [expression]

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

throw([type-ID-list])

type-ID-list是一個(gè)可選項(xiàng),其中包括了一個(gè)或多個(gè)類型的名字,它們之間以逗號(hào)分隔。

例如:

void func() throw(int, some_class_type)

則表明會(huì)拋出intsome_class_type類型異常。

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

void func() throw(...)

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

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

try -- catch

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

catch (exception-declaration) compound-statement

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

舉例:

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;
}

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

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

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

下面介紹一些C++提供的標(biāo)準(zhǔn)異常

namespace std
{
//exception派生
class logic_error; //邏輯錯(cuò)誤,在程序運(yùn)行前可以檢測(cè)出來(lái)

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

//exception派生
class runtime_error; //運(yùn)行時(shí)錯(cuò)誤,僅在程序運(yùn)行中檢測(cè)到

//runtime_error派生
class range_error; //違反后置條件
class overflow_error; //報(bào)告一個(gè)算術(shù)溢出
class bad_alloc; //存儲(chǔ)分配錯(cuò)誤
}

在C++標(biāo)準(zhǔn)庫(kù)頭文件<exception>申明了幾個(gè)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 是所有標(biāo)準(zhǔn)庫(kù)拋出的異常的基類。
uncaught_exception() 函數(shù)在異常被拋出卻沒(méi)有被捕獲時(shí)返回true,其它情況返回false
terminate() 在異常處理陷入了不可恢復(fù)狀態(tài),如:重入時(shí)被調(diào)用。
unexpected() 在函數(shù)拋出一個(gè)沒(méi)有在“異常規(guī)格申明”中申明的異常時(shí)被調(diào)用。

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

在介紹了EH的基本知識(shí)后讓我們來(lái)看看EH是如何工作的。

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

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

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

例如:

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

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

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

return 0;
}

該程序在運(yùn)行時(shí)會(huì)打印如下信息:

捕獲一個(gè)int型異常
捕獲任意類型異常


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

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

例如:

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

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

例如:

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

另外,在構(gòu)造函數(shù)中拋出異常并不會(huì)引發(fā)析構(gòu)函數(shù)。這一點(diǎn)要十分注意。因?yàn)檫@也會(huì)產(chǎn)生資源泄露問(wè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)生的,因此其不會(huì)引發(fā)其析構(gòu)函數(shù)的調(diào)用。于是就如程序所示,產(chǎn)生了內(nèi)存泄露問(wèn)題。對(duì)于這種問(wèn)題,最好的解決辦法還是使用auto_ptr

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

前面說(shuō)到要“找到一個(gè)與異常對(duì)象類型像匹配的異常申明”。事實(shí)上,這種匹配并不要求的十分準(zhǔn)確。
考慮如下例子:

#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


為什么會(huì)這樣呢。因?yàn)槿绻惓伋鲆粋€(gè)派生類對(duì)象,而恰好又其基類所捕獲到。那么該對(duì)象會(huì)被做"切片"處理。也就是說(shuō)相對(duì)于基類,派生元素會(huì)被割下。在例子中derived的vptr會(huì)被設(shè)為base的virtual table。因此虛函數(shù)what就會(huì)呈現(xiàn)出這種行為。而當(dāng)通過(guò)引用捕獲時(shí),得到的僅僅是其地址,對(duì)象不會(huì)被做切片處理。vptr因此也就不會(huì)發(fā)生變化,所以what仍然呈現(xiàn)出來(lái)derived的行為。

因此,這也就提醒我們將基類處理放在最后,在實(shí)際中更有意義。因?yàn)檫@樣可以盡可能的在前面的處理中保存信息。

posted on 2007-10-18 15:38 安帛偉 閱讀(505) 評(píng)論(0)  編輯 收藏 引用

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久久伊人欧美| 国产精品夫妻自拍| 妖精成人www高清在线观看| 国产亚洲精品久久久久动| 欧美韩国在线| 久久精品国产2020观看福利| 性感少妇一区| 欧美成人精品h版在线观看| 亚洲激情欧美| 亚洲尤物在线视频观看| 亚洲欧美日韩国产| 免费观看在线综合| 国产精品久久国产愉拍| 伊人一区二区三区久久精品| 一本大道av伊人久久综合| 老司机久久99久久精品播放免费| 亚洲精品免费在线| 久久三级福利| 国产午夜精品全部视频在线播放| 在线视频精品| 亚洲国产天堂久久国产91| 久久精品欧美| 国产精品久久久久久久久免费桃花| 在线播放日韩专区| 久久久久国产精品厨房| 午夜精品国产更新| 久久久亚洲影院你懂的| 免费看亚洲片| 久久亚洲捆绑美女| 欧美午夜不卡影院在线观看完整版免费| 国产精品美女主播在线观看纯欲| 在线国产欧美| 欧美一区永久视频免费观看| 亚洲国产精品视频一区| 午夜精品免费在线| 欧美日韩日韩| 亚洲人永久免费| 久久久99精品免费观看不卡| 一区二区三区视频在线播放| 欧美成人精品福利| 在线观看成人av电影| 欧美亚洲午夜视频在线观看| 亚洲精品小视频在线观看| 久热成人在线视频| 国产欧美精品日韩精品| 亚洲欧美一区二区精品久久久| 亚洲精品黄色| 欧美高清视频在线| 在线免费高清一区二区三区| 性18欧美另类| 亚洲欧美欧美一区二区三区| 国产精品高潮在线| 一区二区三区国产盗摄| 亚洲激情亚洲| 欧美精品91| 亚洲精品美女久久7777777| 另类成人小视频在线| 久久99在线观看| 国产主播精品在线| 麻豆9191精品国产| 久久亚洲免费| 亚洲三级免费电影| 亚洲免费久久| 国产精品久久久久久久久| 一本色道久久综合精品竹菊| 亚洲国产精品久久| 欧美视频一区| 亚洲欧美一区二区三区极速播放| 一区二区三区毛片| 国产三区二区一区久久| 久久久久久穴| 欧美高清视频www夜色资源网| 一区二区三区日韩在线观看| 一区二区不卡在线视频 午夜欧美不卡' | 欧美视频在线视频| 中文在线资源观看视频网站免费不卡| 亚洲精品久久久久久久久久久久 | 久久综合网hezyo| 亚洲欧洲美洲综合色网| 99视频精品全国免费| 国产精品中文在线| 国产精品综合色区在线观看| 国产精品电影网站| 欧美一区二区私人影院日本| 久久久久久久一区二区三区| 亚洲精品欧洲精品| 亚洲专区在线| 亚洲青涩在线| 亚洲欧美www| 最新中文字幕一区二区三区| aa日韩免费精品视频一| 国产日韩精品综合网站| 欧美高潮视频| 国产精品久久久久久久9999| 欧美成人精品不卡视频在线观看| 欧美久久久久| 久久美女性网| 国产精品a级| 欧美99久久| 国产精品视频yy9299一区| 欧美 日韩 国产 一区| 国产精品成人播放| 亚洲国产日韩一区| 国内外成人免费视频| 欧美激情小视频| 国产精品久久久久99| 亚洲高清免费在线| 国产自产精品| 在线亚洲精品福利网址导航| 亚洲黄色高清| 久久久国产视频91| 欧美在线观看一区| 欧美日韩在线高清| 亚洲国产91| 亚洲第一天堂av| 欧美亚洲在线观看| 欧美一级久久| 国产精品美女久久福利网站| 亚洲福利国产精品| 一区二区三区在线观看国产| 性欧美大战久久久久久久久| 亚洲一区在线直播| 欧美日韩国产bt| 亚洲国产cao| 亚洲另类黄色| 猛男gaygay欧美视频| 久久久久久久久久看片| 国产麻豆一精品一av一免费| 亚洲夜间福利| 欧美一级二级三级蜜桃| 国产精品私拍pans大尺度在线| 99pao成人国产永久免费视频| 亚洲日本成人女熟在线观看| 久久亚洲精选| 亚洲电影免费在线| 亚洲精品国产精品国自产观看浪潮| 久久久无码精品亚洲日韩按摩| 久久综合九色| 亚洲韩国青草视频| 欧美国产亚洲另类动漫| 亚洲精品影院| 亚洲在线播放| 国产欧美综合在线| 欧美自拍偷拍午夜视频| 欧美1区视频| 一区二区三区日韩在线观看| 国产精品v片在线观看不卡| 亚洲午夜激情网页| 老司机精品视频一区二区三区| av成人国产| 欧美精品一区二区在线观看| 亚洲美女在线观看| 欧美亚洲尤物久久| 伊人久久噜噜噜躁狠狠躁| 蜜桃av综合| 亚洲精品一区二区在线观看| 午夜精品久久久久久久久久久久 | 亚洲免费视频一区二区| 国产精品私拍pans大尺度在线| 欧美一级在线亚洲天堂| 嫩草成人www欧美| 亚洲视频一二区| 国产精品视频午夜| 噜噜噜噜噜久久久久久91| 亚洲激情在线| 欧美有码在线视频| 亚洲激情社区| 国产精品每日更新| 女同性一区二区三区人了人一| 亚洲视频一区二区免费在线观看| 欧美在线视频a| 亚洲精品中文字幕有码专区| 国产乱码精品一区二区三区五月婷| 久久久久综合网| 亚洲一区二区三区四区在线观看| 欧美成人r级一区二区三区| 亚洲一区欧美二区| 亚洲国产日韩欧美| 国产丝袜美腿一区二区三区| 欧美日韩成人在线视频| 久久久久免费视频| 亚洲天堂久久| 亚洲欧洲精品一区| 鲁鲁狠狠狠7777一区二区| 亚洲欧美日韩网| 99这里只有精品| 亚洲大片av| 国产一区二区三区高清在线观看| 欧美剧在线观看| 久久亚洲风情| 久久精品日韩一区二区三区| 亚洲欧美国产精品桃花| 亚洲精品一区久久久久久| 欧美成人精品影院| 久久尤物视频| 久久久97精品| 久久免费观看视频| 久久丁香综合五月国产三级网站| 亚洲色在线视频| 夜夜爽夜夜爽精品视频|