Существуют ли методы/библиотеки, которые позволяют гибко иметь иерархию классов (которая имеет функции virtual
), но, как только были определены типы объектов во время выполнения, разрешена девиртуализация вызовов функций?C++ devirtualization во время выполнения?
Для простого примера предположим, что у меня есть программа, которая считывает типы формы (круг, прямоугольник, треугольник и т.д.) из некоторого файла конфигурации, чтобы построить структуру некоторых данных указанных форм (например, vector<shape*>
):
class shape {
public:
virtual void draw() const = 0;
// ...
};
class circle : public shape {
public:
void draw() const;
// ...
};
// ...
vector<shape*> shapes;
Очевидно, что если я хочу, чтобы нарисовать все фигуры, я могу сделать:
for (auto&& s : shapes)
s->draw();
Каждый раз такое делается итерация над shapes
, вызовом virtual
функции сделан для вызова draw()
для каждый форма.
Но предположим, что один раз shapes
создан, это never собирается снова меняться на всю жизнь программы; и далее предположим, что draw()
будет называться раз. Было бы хорошо, если после того, как известны фигуры, был способ «девиртуализировать» вызовы draw()
во время выполнения.
Я знаю о методах оптимизации для devirtualize virtual
вызовов функций в время компиляции, но я не с просьбой об этом.
Я был бы очень удивлен, если бы был умный взлом, чтобы сделать это на C++ напрямую, поскольку одним из способов сделать это было бы изменение машинного кода в памяти во время выполнения. Но есть ли там библиотека C++, которая позволяет такое?
Я представляю себе что-то вроде этого возможно возможно через LLVM, поскольку это позволяет генерировать машинный код во время выполнения. Кто-нибудь использовал LLVM для этого? Возможно, структура, расположенная поверх LLVM?
Примечание: раствор должен быть кросс-платформенный, то есть, по меньшей мере, с помощью GCC/лязг и VC++.
Как бы эта девиртуализация работала, если в списке были разные фигуры? Будет ли это (концептуально) заменить вызов s-> draw() внутри цикла for с помощью (if type == Circle) s-> circle :: draw(); else if (type == Square) s-> square :: draw(); тип инструкций? Если это так, я не уверен, что это обязательно будет более эффективным. –
Если дальнейших подклассов формы нет, вы можете сами «девиртуализировать» себя, наложив друг на друга. Но, пока есть два или более подкласса, если компилятор не может каким-то образом доказать себе, что конкретный кусок кода будет использовать только определенный подкласс, он должен использовать вызов виртуальной функции. Это маловероятно, но возможно. После «auto x = новый круг»; компилятор знает, что, поскольку у него есть «x» под рукой, «x-> draw()» можно безопасно девиртуализировать, и многие компиляторы, вероятно, уже делают это. К сожалению, масштабы таких оптимизаций, как правило, довольно малы. –
Выполняли ли вы профилирование, указывающее на то, что прыжок vtable имеет измеримое влияние на производительность? vtable звонки по-прежнему * очень * дешево. По словам Дональда Кнута, преждевременная оптимизация - это корень всего зла. – Dai