第9集C++的異常對(duì)象如何被傳遞

字號(hào):

在相遇篇的第4集文章中,曾經(jīng)講到過(guò)在C++的異常處理模型中,是用“對(duì)象”來(lái)描述程序中出現(xiàn)的異常,并且在那篇文章中詳細(xì)討論了這樣做所帶來(lái)的諸多好處,其中之一呢就是:對(duì)象一般都很好地實(shí)現(xiàn)了對(duì)象的構(gòu)造、對(duì)象的銷毀、對(duì)象的轉(zhuǎn)存復(fù)制,這為異常處理模型中異常對(duì)象的轉(zhuǎn)存復(fù)制和對(duì)象銷毀提供了很好的支持。是的沒(méi)錯(cuò),但是所謂的異常對(duì)象到底是如何被復(fù)制和傳遞呢?從本篇文章開(kāi)始,和接下來(lái)的幾篇文章中,主人公阿愚將和大家一同比較深入地探討這個(gè)問(wèn)題,并力求弄清每一個(gè)重要的細(xì)節(jié)。
    概述
    呵呵!sorry,居然忘了闡述一下定義。那就是“C++的異常對(duì)象被傳遞”指的是什么?想當(dāng)然大家也都知道,這指的就是異常出現(xiàn)時(shí)throw出的異常對(duì)象如何被傳遞到catch block塊中,catch block中的異常處理模塊再根據(jù)異常對(duì)象提供的異常信息做出相應(yīng)的處理。程序員朋友們也許認(rèn)為這很簡(jiǎn)單,其實(shí)說(shuō)簡(jiǎn)單也好像不太簡(jiǎn)單,因?yàn)檫@種對(duì)象的傳遞或復(fù)制可能發(fā)生在同一個(gè)函數(shù)的不同程序塊作用域間,也有可能是從當(dāng)前的函數(shù)傳遞到上一個(gè)函數(shù)中,更有可能是把異常對(duì)象傳遞復(fù)制到上上(甚至更多層)的函數(shù)中。
    異常對(duì)象的傳遞有點(diǎn)類似于函數(shù)調(diào)用過(guò)程中的參數(shù)傳遞的過(guò)程。瞧!catch關(guān)鍵字的語(yǔ)法不就跟函數(shù)的定義有點(diǎn)類似嗎?作為入?yún)⒌漠惓?duì)象也是用括號(hào)被括起來(lái)的,只不過(guò)catch只能是擁有一個(gè)參數(shù)。另外連catch(…)語(yǔ)法也是抄襲函數(shù)定義的方式,表示接受任意類型的數(shù)據(jù)對(duì)象。
    C++程序中函數(shù)的調(diào)用是通過(guò)“?!眮?lái)實(shí)現(xiàn)的,其中參數(shù)的傳遞也是保存到棧中,以實(shí)現(xiàn)兩個(gè)函數(shù)間的數(shù)據(jù)共享。那么異常對(duì)象的傳遞呢?當(dāng)然也是通過(guò)棧,其實(shí)這是很明顯的一件事情,因?yàn)楫惓?duì)象本身肯定是局部變量,因此它也肯定是被保存在棧中的。不過(guò)異常對(duì)象的傳遞畢竟還是與函數(shù)參數(shù)的傳遞有很大的不同,函數(shù)參數(shù)的傳遞是嚴(yán)謹(jǐn)?shù)摹⒁患?jí)一級(jí)的對(duì)象數(shù)據(jù)的壓棧過(guò)程和出棧過(guò)程;但異常對(duì)象的傳遞卻遠(yuǎn)比這要復(fù)雜些,因?yàn)樗@是逆序的,屬于局部變量的異常對(duì)象可能要往上層(或更上層)函數(shù)傳遞,它的過(guò)程是一個(gè)跳躍式的或比較混亂的過(guò)程。關(guān)于異常對(duì)象的傳遞具體是如何實(shí)現(xiàn)的,在愛(ài)的秘密篇中分析C++異常處理模型的實(shí)現(xiàn)時(shí)會(huì)再做詳細(xì)闡述。而目前需要搞清楚的是,這個(gè)過(guò)程中所需要遵從的一些規(guī)律或標(biāo)準(zhǔn)。
    函數(shù)的參數(shù)的傳遞一般有指針、傳值和引用三種方式,同樣,異常對(duì)象的傳遞也同樣有這三種方式的區(qū)別?,F(xiàn)在開(kāi)始,主人公阿愚分別講述每一種方式下異常對(duì)象是如何被傳遞的,不過(guò)在正式開(kāi)始之前,還是先簡(jiǎn)要總結(jié)函數(shù)調(diào)用的過(guò)程,以及這過(guò)程棧的變化。因?yàn)檫@對(duì)隨后的具體分析和理解也許大有幫助。
    函數(shù)的調(diào)用過(guò)程與“?!?BR>    C++程序員對(duì)這個(gè)過(guò)程肯定非常熟悉,因此這里不做細(xì)致的講述,只做一個(gè)概要性的總結(jié)。
    (1) 函數(shù)的調(diào)用過(guò)程實(shí)質(zhì)上利用棧來(lái)實(shí)現(xiàn)的指令(eip)執(zhí)行遠(yuǎn)程轉(zhuǎn)移和返回的過(guò)程;它在CPU指令級(jí)別上就得到了支持(CALL和RET指令);
    (2) 每個(gè)線程都有一個(gè)自己的棧,因此每個(gè)線程的函數(shù)調(diào)用執(zhí)行是相互不受影響的;
    (3) C和C++中的函數(shù)參數(shù)的入棧順序一般是從右到左進(jìn)行;
    (4) C++中的函數(shù)的參數(shù)的傳遞一般有指針、傳值和引用三種方式;
    (5) C和C++中函數(shù)的返回值一般都是保存到EAX寄存器中返回的;
    (6) C和C++中函數(shù)中尋址參數(shù)和局部變量,一般都是通過(guò)EBP寄存器加上偏移來(lái)進(jìn)行的,如參數(shù)一般是:[EBP+XX],而局部變量則一般是:[EBP-XX];
    (7) 在程序運(yùn)行時(shí),EBP中的值一般是指向當(dāng)前的函數(shù)調(diào)用幀,而ESP一般指向棧頂。
    如果對(duì)上面論述有不太清楚或不太熟悉的朋友,建議先看看專門講述C++設(shè)計(jì)和編程方面的書籍。
    總結(jié)
     (1) 與函數(shù)的參數(shù)的傳遞類似, C++的異常對(duì)象的傳遞也分指針、傳值和引用三種方式;
    (2) 與函數(shù)的參數(shù)的傳遞不同的是,異常對(duì)象的傳遞是向上逆序的,而且是跳躍式的。
    下一篇文章詳細(xì)介紹C++的異常對(duì)象按傳值的方式被復(fù)制和傳遞。朋友們,不要錯(cuò)過(guò),請(qǐng)繼續(xù)吧!