Могут ли компиляторы С++ оптимизировать повторные вызовы виртуальных функций на одном и том же указателе?

Предположим, что у меня есть следующий код

void f(PolymorphicType *p)
{
    for (int i = 0; i < 1000; ++i)
    {
        p->virtualMethod(something);
    }
}

Будет ли компилятор сгенерировать разницу кода p vtable для virtualMethod 1 или 1000 раз? Я использую компилятор Microsoft.

изменить

вот сгенерированная сборка для реального случая, на который я смотрю. line->addPoint() - это виртуальный метод, вызывающий озабоченность. У меня нет опыта сборки, поэтому я медленно перехожу к нему...

; 369  :        for (int i = 0; i < numPts; ++i)

    test    ebx, ebx
    je  SHORT [email protected]_SCANNE
    lea edi, DWORD PTR [ecx+32]
    npad    2
[email protected]_SCANNE:

; 370  :        {
; 371  :            double *pts = pPoints[i].SystemXYZ;
; 372  :            line->addPoint(pts[0], pts[1], pts[2]);

    fld QWORD PTR [edi+8]
    mov eax, DWORD PTR [esi]
    mov edx, DWORD PTR [eax+16]
    sub esp, 24                 ; 00000018H
    fstp    QWORD PTR [esp+16]
    mov ecx, esi
    fld QWORD PTR [edi]
    fstp    QWORD PTR [esp+8]
    fld QWORD PTR [edi-8]
    fstp    QWORD PTR [esp]
    call    edx
    add edi, 96                 ; 00000060H
    dec ebx
    jne SHORT [email protected]_SCANNE
[email protected]_SCANNE:

; 365  :        }

Ответы

Ответ 1

В общем, нет, это невозможно. Функция может уничтожить *this и размещение - новый другой объект, полученный из той же базы в этом пространстве.

Изменить: еще проще, функция может просто изменить p. Компилятор не может знать, кто имеет адрес p, если он не является локальным для рассматриваемого блока оптимизации.

Ответ 2

Невозможно вообще, но есть особые случаи, которые можно оптимизировать, особенно при межпроцедурном анализе. VS2012 с полной оптимизацией и оптимизацией всей программы компилирует эту программу:

#include <iostream>

using namespace std;

namespace {
struct A {
  virtual void foo() { cout << "A::foo\n"; }
};

struct B : public A {
  virtual void foo() { cout << "B::foo\n"; }
};

void test(A& a) {
  for (int i = 0; i < 100; ++i)
    a.foo();
}
}

int main() {
  B b;
  test(b);
}

в

01251221  mov         esi,64h  
01251226  jmp         main+10h (01251230h)  
01251228  lea         esp,[esp]  
0125122F  nop  
01251230  mov         ecx,dword ptr ds:[1253044h]  
01251236  mov         edx,12531ACh  
0125123B  call        std::operator<<<std::char_traits<char> > (012516B0h)  
01251240  dec         esi  
01251241  jne         main+10h (01251230h)  

чтобы он эффективно оптимизировал цикл для:

for(int i = 0; i < 100; ++i)
  cout << "B::foo()\n";