LTO, девиртуализация и виртуальные таблицы

Сравнивая виртуальные функции в C ++ и виртуальные таблицы в C, делают ли компиляторы в целом (и для достаточно больших проектов) столь же хорошо работу с девиртуализацией?

Наивно, кажется, что это так. виртуальные функции в C ++ имеют немного больше семантики, поэтому их легче девиртуализировать.

Обновление: Муинг Дак упомянул встраивание девиртуализированных функций. Быстрая проверка показывает пропущенные оптимизации с виртуальными таблицами:

struct vtab {
    int (*f)();
};

struct obj {
    struct vtab *vtab;
    int data;
};

int f()
{
    return 5;
}

int main()
{
    struct vtab vtab = {f};
    struct obj obj = {&vtab, 10};

    printf("%d\n", obj.vtab->f());
}

Мой GCC не будет встроить f, хотя он вызывается напрямую, то есть девиртуализированный. Эквивалент в C ++,

class A
{
public:
    virtual int f() = 0;
};

class B
{
public:
    int f() {return 5;}
};

int main()
{
    B b;
    printf("%d\n", b.f());
}

делает даже встроенным f. Итак, есть первое различие между C и C ++, хотя я не думаю, что добавленная семантика в версии C ++ уместна в этом случае.

Обновление 2: Для девиртуализации в C , компилятор должен доказать, что указатель функции в виртуальной таблице имеет определенное значение. Для девиртуализации в C ++ компилятор должен доказать, что объект является экземпляром определенного класса. Казалось бы, в первом случае доказательство сложнее. Однако виртуальные таблицы обычно модифицируются лишь в очень немногих местах, и, что наиболее важно: просто потому, что это выглядит сложнее, не означает, что компиляторы не так хороши в этом (иначе вы можете утверждать, что xoring обычно быстрее, чем добавление двух целые числа).

15
задан ccom 13 August 2011 в 17:24
поделиться