Существуют ли случаи, когда класс объявляет виртуальные методы и компилятору не нужно использовать vptr? - PullRequest
0 голосов
/ 25 февраля 2010

Мне было интересно, существует ли возможная оптимизация, когда компилятору не нужно присваивать vptr экземпляру объекта, даже если тип объекта является классом с виртуальными методами.

Например, рассмотрим:

#include <iostream>
struct FooBase
{
  virtual void bar()=0;
};

struct FooDerived : public FooBase
{
  virtual void bar() { std::cout << "FooDerived::bar()\n"; }
};

int main()
{
   FooBase* pFoo = new FooDerived();
   pFoo->bar();

  return 0;
}

В этом примере компилятор наверняка знает, какой будет тип pFoo во время компиляции, поэтому ему не нужно использовать vptr для pFoo, верно?Есть ли более интересные случаи, когда компилятор может избежать использования vptr?

Ответы [ 4 ]

4 голосов
/ 25 февраля 2010

Опираясь на Ответ Эндрю Стейна , потому что я думаю, что вы также хотите знать, когда можно избежать так называемых «накладных расходов виртуальных функций во время выполнения». (Накладные расходы есть, но они крошечные , и о них редко стоит беспокоиться.)

Действительно трудно избежать пробела указателя vtable, но сам указатель можно игнорировать, в том числе в вашем примере. Поскольку инициализация pFoo находится в этой области, компилятор знает, что pFoo->bar должен означать FooDerived :: bar , и не нуждается в проверке vtable. Существует также несколько методов кэширования, позволяющих избежать многократного поиска в vtable, от простого до сложного.

4 голосов
/ 25 февраля 2010

Даже в случае, если вы показываете, я сомневаюсь, что любой компилятор сделает то, что вы предлагаете.

Вы используете очень простую программу в одном файле.

Представьте, что у вас есть FooBase и FooDerived в Foo.h и Foo.cpp и main в main.cpp. При компиляции Foo.cpp, как компилятор должен знать, что во всей программе нет необходимости в vtbl. Он не видел main.cpp.

Окончательное определение может быть сделано только во время ссылки, когда слишком поздно и сложно изменить объектный файл, найти все вызовы sizeof (FooDerived) и т. Д.

0 голосов
/ 25 февраля 2010

Компилятор может исключить косвенные издержки при вызовах виртуальных функций, когда он знает, какой именно метод класса будет вызван. Это результат анализа точек на , который делают оптимизирующие компиляторы. Они отслеживают поток данных переменных-указателей, и в любом месте указатель может указывать только на объекты одного типа, он может генерировать вызовы именно для этого типа, статически реализуя семантику виртуальных вызовов (то есть во время компиляции).

Как уже говорили многие, если компилятор не выполняет оптимизацию по времени всей программы / канала связи (становится все более популярной; GCC получает ее в 4.5), он все равно должен генерировать какую-то таблицу виртуальных функций для поддержки отдельной компиляции .

0 голосов
/ 25 февраля 2010

Даже самые современные, глобально оптимизирующие компиляторы все еще придерживаются принципа «независимого перевода». Согласно этому принципу, каждая единица перевода составляется независимо, без каких-либо знаний о любых других единицах перевода, которые могут существовать во всей окончательной программе.

Когда вы объявляете класс с внешней связью, этот класс может использоваться в других единицах перевода. Компилятор не имеет представления о том, как ваш класс может использоваться в этих других единицах перевода. Таким образом, он должен предполагать, что для каждого экземпляра этого класса в общем случае требуется указатель виртуальной таблицы, правильно инициализированный в момент создания.

В вашем примере умный компилятор может выяснить, что динамический тип объекта *pFoo равен FooDerived. Это позволило бы компилятору оптимизировать код: генерировать прямой вызов функции FooDerived::bar в ответ на выражение pFoo->bar() (без использования виртуальной таблицы). Но тем не менее компилятору обычно все равно придется правильно инициализировать указатель виртуальной таблицы в каждом FooDerived объекте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...