第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

C ++中的異常如何工作(在幕后)

C ++中的異常如何工作(在幕后)

繁星coding 2019-12-09 09:47:03
我一直看到人們說例外情況很慢,但我從未見過任何證據(jù)。因此,我將詢問異常在后臺(tái)如何工作,而不是詢問它們是否存在,因此我可以決定何時(shí)使用它們以及它們是否緩慢。據(jù)我所知,異常與執(zhí)行一堆返回是相同的事情,但是它還會(huì)檢查何時(shí)需要停止執(zhí)行返回。如何檢查何時(shí)停止?我正在猜測(cè),并說有第二個(gè)堆棧保存異常類型,然后堆棧位置返回直到到達(dá)那里。我還猜測(cè)唯一一次堆棧接觸是在擲球和每次嘗試/接球。AFAICT使用返回代碼實(shí)現(xiàn)類似行為將花費(fèi)相同的時(shí)間。但這只是一個(gè)猜測(cè),所以我想知道。異常如何真正起作用?
查看完整描述

3 回答

?
慕的地6264312

TA貢獻(xiàn)1817條經(jīng)驗(yàn) 獲得超6個(gè)贊

不用猜測(cè),我決定實(shí)際上是用一小段C ++代碼和稍舊的Linux安裝程序來查看生成的代碼。


class MyException

{

public:

    MyException() { }

    ~MyException() { }

};


void my_throwing_function(bool throwit)

{

    if (throwit)

        throw MyException();

}


void another_function();

void log(unsigned count);


void my_catching_function()

{

    log(0);

    try

    {

        log(1);

        another_function();

        log(2);

    }

    catch (const MyException& e)

    {

        log(3);

    }

    log(4);

}

我使用進(jìn)行了編譯g++ -m32 -W -Wall -O3 -save-temps -c,然后查看了生成的程序集文件。


    .file   "foo.cpp"

    .section    .text._ZN11MyExceptionD1Ev,"axG",@progbits,_ZN11MyExceptionD1Ev,comdat

    .align 2

    .p2align 4,,15

    .weak   _ZN11MyExceptionD1Ev

    .type   _ZN11MyExceptionD1Ev, @function

_ZN11MyExceptionD1Ev:

.LFB7:

    pushl   %ebp

.LCFI0:

    movl    %esp, %ebp

.LCFI1:

    popl    %ebp

    ret

.LFE7:

    .size   _ZN11MyExceptionD1Ev, .-_ZN11MyExceptionD1Ev

_ZN11MyExceptionD1Ev是MyException::~MyException(),因此編譯器決定需要析構(gòu)函數(shù)的非內(nèi)聯(lián)副本。


.globl __gxx_personality_v0

.globl _Unwind_Resume

    .text

    .align 2

    .p2align 4,,15

.globl _Z20my_catching_functionv

    .type   _Z20my_catching_functionv, @function

_Z20my_catching_functionv:

.LFB9:

    pushl   %ebp

.LCFI2:

    movl    %esp, %ebp

.LCFI3:

    pushl   %ebx

.LCFI4:

    subl    $20, %esp

.LCFI5:

    movl    $0, (%esp)

.LEHB0:

    call    _Z3logj

.LEHE0:

    movl    $1, (%esp)

.LEHB1:

    call    _Z3logj

    call    _Z16another_functionv

    movl    $2, (%esp)

    call    _Z3logj

.LEHE1:

.L5:

    movl    $4, (%esp)

.LEHB2:

    call    _Z3logj

    addl    $20, %esp

    popl    %ebx

    popl    %ebp

    ret

.L12:

    subl    $1, %edx

    movl    %eax, %ebx

    je  .L16

.L14:

    movl    %ebx, (%esp)

    call    _Unwind_Resume

.LEHE2:

.L16:

.L6:

    movl    %eax, (%esp)

    call    __cxa_begin_catch

    movl    $3, (%esp)

.LEHB3:

    call    _Z3logj

.LEHE3:

    call    __cxa_end_catch

    .p2align 4,,3

    jmp .L5

.L11:

.L8:

    movl    %eax, %ebx

    .p2align 4,,6

    call    __cxa_end_catch

    .p2align 4,,6

    jmp .L14

.LFE9:

    .size   _Z20my_catching_functionv, .-_Z20my_catching_functionv

    .section    .gcc_except_table,"a",@progbits

    .align 4

.LLSDA9:

    .byte   0xff

    .byte   0x0

    .uleb128 .LLSDATT9-.LLSDATTD9

.LLSDATTD9:

    .byte   0x1

    .uleb128 .LLSDACSE9-.LLSDACSB9

.LLSDACSB9:

    .uleb128 .LEHB0-.LFB9

    .uleb128 .LEHE0-.LEHB0

    .uleb128 0x0

    .uleb128 0x0

    .uleb128 .LEHB1-.LFB9

    .uleb128 .LEHE1-.LEHB1

    .uleb128 .L12-.LFB9

    .uleb128 0x1

    .uleb128 .LEHB2-.LFB9

    .uleb128 .LEHE2-.LEHB2

    .uleb128 0x0

    .uleb128 0x0

    .uleb128 .LEHB3-.LFB9

    .uleb128 .LEHE3-.LEHB3

    .uleb128 .L11-.LFB9

    .uleb128 0x0

.LLSDACSE9:

    .byte   0x1

    .byte   0x0

    .align 4

    .long   _ZTI11MyException

.LLSDATT9:

驚喜!正常代碼路徑上根本沒有多余的指令。相反,編譯器生成了額外的離線修正代碼塊,這些代碼塊通過函數(shù)末尾的表引用(實(shí)際上放在可執(zhí)行文件的單獨(dú)部分中)。所有工作都是由標(biāo)準(zhǔn)庫(kù)在后臺(tái)基于這些表(_ZTI11MyExceptionis typeinfo for MyException)完成的。


好吧,這實(shí)際上對(duì)我來說并不令人驚訝,我已經(jīng)知道該編譯器是如何做到的。繼續(xù)匯編輸出:


    .text

    .align 2

    .p2align 4,,15

.globl _Z20my_throwing_functionb

    .type   _Z20my_throwing_functionb, @function

_Z20my_throwing_functionb:

.LFB8:

    pushl   %ebp

.LCFI6:

    movl    %esp, %ebp

.LCFI7:

    subl    $24, %esp

.LCFI8:

    cmpb    $0, 8(%ebp)

    jne .L21

    leave

    ret

.L21:

    movl    $1, (%esp)

    call    __cxa_allocate_exception

    movl    $_ZN11MyExceptionD1Ev, 8(%esp)

    movl    $_ZTI11MyException, 4(%esp)

    movl    %eax, (%esp)

    call    __cxa_throw

.LFE8:

    .size   _Z20my_throwing_functionb, .-_Z20my_throwing_functionb

在這里,我們看到了引發(fā)異常的代碼。盡管沒有僅僅因?yàn)榭赡芤l(fā)異常而產(chǎn)生了額外的開銷,但是在實(shí)際引發(fā)和捕獲異常方面顯然存在很多開銷。其中大多數(shù)隱藏在中__cxa_throw,該必須:


在異常表的幫助下遍歷堆棧,直到找到該異常的處理程序?yàn)橹埂?/p>

展開堆棧,直到到達(dá)該處理程序?yàn)橹埂?/p>

實(shí)際調(diào)用處理程序。

將其與僅返回值的成本進(jìn)行比較,您會(huì)看到為什么僅將異常用于特殊收益的原因。


最后,匯編文件的其余部分:


    .weak   _ZTI11MyException

    .section    .rodata._ZTI11MyException,"aG",@progbits,_ZTI11MyException,comdat

    .align 4

    .type   _ZTI11MyException, @object

    .size   _ZTI11MyException, 8

_ZTI11MyException:

    .long   _ZTVN10__cxxabiv117__class_type_infoE+8

    .long   _ZTS11MyException

    .weak   _ZTS11MyException

    .section    .rodata._ZTS11MyException,"aG",@progbits,_ZTS11MyException,comdat

    .type   _ZTS11MyException, @object

    .size   _ZTS11MyException, 14

_ZTS11MyException:

    .string "11MyException"

typeinfo數(shù)據(jù)。


    .section    .eh_frame,"a",@progbits

.Lframe1:

    .long   .LECIE1-.LSCIE1

.LSCIE1:

    .long   0x0

    .byte   0x1

    .string "zPL"

    .uleb128 0x1

    .sleb128 -4

    .byte   0x8

    .uleb128 0x6

    .byte   0x0

    .long   __gxx_personality_v0

    .byte   0x0

    .byte   0xc

    .uleb128 0x4

    .uleb128 0x4

    .byte   0x88

    .uleb128 0x1

    .align 4

.LECIE1:

.LSFDE3:

    .long   .LEFDE3-.LASFDE3

.LASFDE3:

    .long   .LASFDE3-.Lframe1

    .long   .LFB9

    .long   .LFE9-.LFB9

    .uleb128 0x4

    .long   .LLSDA9

    .byte   0x4

    .long   .LCFI2-.LFB9

    .byte   0xe

    .uleb128 0x8

    .byte   0x85

    .uleb128 0x2

    .byte   0x4

    .long   .LCFI3-.LCFI2

    .byte   0xd

    .uleb128 0x5

    .byte   0x4

    .long   .LCFI5-.LCFI3

    .byte   0x83

    .uleb128 0x3

    .align 4

.LEFDE3:

.LSFDE5:

    .long   .LEFDE5-.LASFDE5

.LASFDE5:

    .long   .LASFDE5-.Lframe1

    .long   .LFB8

    .long   .LFE8-.LFB8

    .uleb128 0x4

    .long   0x0

    .byte   0x4

    .long   .LCFI6-.LFB8

    .byte   0xe

    .uleb128 0x8

    .byte   0x85

    .uleb128 0x2

    .byte   0x4

    .long   .LCFI7-.LCFI6

    .byte   0xd

    .uleb128 0x5

    .align 4

.LEFDE5:

    .ident  "GCC: (GNU) 4.1.2 (Ubuntu 4.1.2-0ubuntu4)"

    .section    .note.GNU-stack,"",@progbits

甚至更多的異常處理表,以及各種額外的信息。


因此,至少對(duì)于Linux上的GCC,得出的結(jié)論是:無論是否引發(fā)異常,開銷都是額外的空間(用于處理程序和表),加上在引發(fā)異常時(shí)解析表并執(zhí)行處理程序的額外開銷。如果使用異常而不是錯(cuò)誤代碼,并且錯(cuò)誤很少見,則錯(cuò)誤速度會(huì)更快,因?yàn)槟辉傩枰M(jìn)行錯(cuò)誤測(cè)試。


查看完整回答
反對(duì) 回復(fù) 2019-12-09
?
茅侃侃

TA貢獻(xiàn)1842條經(jīng)驗(yàn) 獲得超21個(gè)贊

例外是緩在舊時(shí)代真的。
在大多數(shù)現(xiàn)代編譯器中,這不再成立。

注意:僅僅因?yàn)槲覀冇欣獠⒉灰馕吨覀円膊粫?huì)使用錯(cuò)誤代碼。如果可以在本地處理錯(cuò)誤,請(qǐng)使用錯(cuò)誤代碼。當(dāng)錯(cuò)誤需要更多上下文來更正時(shí),請(qǐng)使用異常:我在這里雄辯地寫道:指導(dǎo)異常處理策略的原則是什么?

當(dāng)不使用任何異常時(shí),異常處理代碼的成本實(shí)際上為零。

引發(fā)異常時(shí),將完成一些工作。
但是您必須將其與返回錯(cuò)誤代碼并一路檢查它們以指出可以處理錯(cuò)誤的位置的開銷進(jìn)行比較。兩者都花費(fèi)更多的時(shí)間來編寫和維護(hù)。

對(duì)于新手來說也有一個(gè)陷阱:
盡管Exception對(duì)象應(yīng)該很小,但是有些人卻在其中放了很多東西。然后,您需要復(fù)制異常對(duì)象。解決方案有兩個(gè)方面:

  • 不要把多余的東西放在例外中。

  • 通過const引用捕獲。

在我看來,我敢打賭,帶有例外的同一代碼將比沒有例外的代碼更有效率,或者至少具有可比性(但具有檢查功能錯(cuò)誤結(jié)果的所有額外代碼)。請(qǐng)記住,您沒有免費(fèi)獲得任何東西,編譯器正在生成您應(yīng)首先編寫的用于檢查錯(cuò)誤代碼的代碼(通常,編譯器比人類更有效)。


查看完整回答
反對(duì) 回復(fù) 2019-12-09
?
天涯盡頭無女友

TA貢獻(xiàn)1831條經(jīng)驗(yàn) 獲得超9個(gè)贊

有多種方法可以實(shí)現(xiàn)異常,但是通常它們將依賴于操作系統(tǒng)的某些基礎(chǔ)支持。在Windows上,這是結(jié)構(gòu)化異常處理機(jī)制。

有關(guān)代碼項(xiàng)目的詳細(xì)信息,進(jìn)行了不錯(cuò)的討論:C ++編譯器如何實(shí)現(xiàn)異常處理

發(fā)生異常的開銷是因?yàn)?,如果異常傳播到該范圍之外,則編譯器必須生成代碼來跟蹤必須在每個(gè)堆棧幀(或更確切地說是范圍)中銷毀哪些對(duì)象。如果函數(shù)在堆棧上沒有需要調(diào)用析構(gòu)函數(shù)的局部變量,則它不應(yīng)因異常處理而降低性能。

使用返回碼一次只能解開堆棧的單個(gè)級(jí)別,而如果在中間堆棧幀中無事可做,則異常處理機(jī)制可以在一次操作中進(jìn)一步跳回堆棧。


查看完整回答
反對(duì) 回復(fù) 2019-12-09
  • 3 回答
  • 0 關(guān)注
  • 815 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)