虚拟函数编译器优化C ++

Igo*_*vic 5 c++ virtual function

class Base 
{
public:
    virtual void fnc(size_t nm) 
    {
        // do some work here
    }

    void process()
    {
        for(size_t i = 0; i < 1000; i++)
        {
            fnc(i);
        }
    }
}  
Run Code Online (Sandbox Code Playgroud)

考虑到每次在循环内被调用时,c ++编译器都将是同一个函数,因此c ++编译器能否并且是否将从进程功能中优化对fnc函数的调用?还是每次调用该函数都会从vtable获取函数地址?

Jos*_*and 4

我在 godbolt.org 上查看了一个示例。结果是不,没有一个编译器优化它。

这是测试源:

class Base 
{
public:
// made it pure virtual to decrease clutter
    virtual void fnc(int nm) =0;
    void process()
    {
        for(int i = 0; i < 1000; i++)
        {
            fnc(i);
        }
    }
};

void test(Base* b ) {
    return b->process();
}
Run Code Online (Sandbox Code Playgroud)

和生成的asm:

test(Base*):
        push    rbp       ; setup function call 
        push    rbx
        mov     rbp, rdi  ; Base* rbp 
        xor     ebx, ebx  ; int ebx=0;
        sub     rsp, 8    ; advance stack ptr
.L2:
        mov     rax, QWORD PTR [rbp+0]  ; read 8 bytes from our Base*
                                        ; rax now contains vtable ptr 
        mov     esi, ebx                ; int parameter for fnc
        add     ebx, 1                  ; i++
        mov     rdi, rbp                ; (Base*) this parameter for fnc
        call    [QWORD PTR [rax]]       ; read vtable and call fnc
        cmp     ebx, 1000               ; back to the top of the loop 
        jne     .L2
        add     rsp, 8                  ; reset stack ptr and return
        pop     rbx
        pop     rbp
        ret
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,它在每次调用时都会读取 vtable。我猜这是因为编译器无法证明您没有更改函数调用内的虚函数表(例如,如果您调用新的放置或一些愚蠢的东西),因此,从技术上讲,虚拟函数调用可能会在迭代之间发生变化。