关于在if else链中使用goto有什么特别之处

Nic*_*ick 15 c++ optimization

我正在观看Alexandrescu的视频,他有以下代码片段:

 // an example implementation of a single threaded shared_ptr
 ~SingleThreadPtr() { 
    if(!c_) {
       soSueMe: delete p_;
    } else if(--*c_ == 0) {
       delete c_;
       goto soSueMe;
    }
 }
Run Code Online (Sandbox Code Playgroud)

这是https://youtu.be/Qq_WaiwzOtI?t=36m44s.他说,"我使用我着名的'goto soSueMe'构造",并说"试着写下这个没有goto和[..]你会发现它很难".

这里有什么困难?是不是以下相同,显然不难,更可读:

 // an example implementation of a single threaded shared_ptr
 ~SingleThreadPtr() { 
    if(!c_) {
       delete p_;
    } else if(--*c_ == 0) {
       delete c_;
       delete p_;
    }
 }
Run Code Online (Sandbox Code Playgroud)

或者是不是一样的(从而加强了反对的论点goto)?什么样的黑客黑魔法伏都教在这里?

don*_*mus 12

这里的关键是,shared_ptr的析构函数被称为相对频繁,一般内嵌,这是为了减少内联析构函数大小(以企图goto比删除调用小得多).

例如,delete p_编译时的析构函数调用可能类似于:

LBB5_8:
    movq    -16(%rbp), %rax         ## 8-byte Reload
    movq    (%rax), %rcx
    cmpq    $0, %rcx
    movq    %rcx, -24(%rbp)         ## 8-byte Spill
    je  LBB5_4
    movq    -24(%rbp), %rax         ## 8-byte Reload
    movq    %rax, %rdi
    callq   __ZdlPv                 
LBB5_4:
Run Code Online (Sandbox Code Playgroud)

(callq __ZdlPv最后调用底层对象析构函数).

尽管goto看起来只是像这样:

LBB5_8:
    jmp LBB5_2
Run Code Online (Sandbox Code Playgroud)

因此,通过分支而不是重复delete p_声明,代码化显着减少.

随附的演示文稿可能证明是有用的阅读(虽然简洁).

  • 听起来这只是编译器的糟糕优化. (4认同)