簡體   English   中英

調用不是內聯的常量指針到成員函數

[英]Call to constant pointer-to-member function not being inlined

現在,我知道內聯沒有保證,但......

鑒於以下內容:

struct Base {
    virtual int f() = 0;
};

struct Derived : public Base {
    virtual int f() final override {
        return 42;
    }
};

extern Base* b;

我們有:

int main() {
    return static_cast<Derived*>(b)->f();
}

編譯為:

main:
    movl    $42, %eax
    ret

然而...

int main() {
    return (static_cast<Derived*>(b)->*(&Derived::f))();
}

編譯為:

main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    b, %eax
    movl    (%eax), %edx
    movl    %eax, (%esp)
    call    *(%edx)
    leave
    ret

哪個真的很難過。

為什么沒有內聯PMF的調用? PMF是一個不變的表達!

這里的問題是,在第一種情況下,基於類型的虛擬化將間接調用轉換為直接調用。 當您添加成員指針時,不能使用基於類型的devirtualization(因為它通過前端向下傳遞到有關所調用的類型和虛方法的優化信息,在本例中並非簡單地知道)。 通過知道B是一個類並且知道只有在構造它之后才能調用它的成員, GCC可以能夠不斷地將實際訪問權限折疊到virutal table 目前它沒有做這樣的分析。

我建議填寫GCC bugzilla的增強請求。

並不總是可以將指針內聯到函數中(除非編譯器能夠弄清楚指針實際指向的是什么,這通常很困難,因此編譯器可能會在您預期之前“放棄”)。

編輯

擴展我的答案:所有編譯器的首要任務是生成CORRECT代碼(盡管有時這也不會發生!)。 優化(例如內聯函數)是編譯器僅在“安全”時才會執行的操作。 編譯器可能不完全“理解”上面的表達式確實是一個常量表達式,因此可以回到“讓我們做安全的事情”(通過虛函數表調用,而不是內聯函數)。 指向虛擬成員函數的指針在C ++中是一個非常棘手的主題。

這確實有點煩人,但這並不奇怪。

大多數編譯器轉換通過模式匹配來工作:識別模式並應用轉換。 那么這可能不會被優化的原因是什么? 好吧,也許只是簡單地說沒有根據這種模式編寫的轉換。

這里最具體的是,問題可能是關於&Derived::f ,gcc和clang都有一個特定的表示形式用於指向虛函數的指針:它們使用指向執行虛擬分辨率的trampoline函數的指針。 因此,可能只是這個trampoline函數是一個嵌套太多,編譯器無法透視。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM