Потеря производительности для работы с интерфейсами в C++?

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

42
задан Suma 16 January 2009 в 09:03
поделиться

16 ответов

Короткий Ответ: Нет.

Длинный Ответ: Это не базовый класс или число предков, которых класс имеет в его иерархии, которая влияет на него скорость. Единственной вещью является стоимость вызова метода.

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

, Если Вы не пишете некоторой hyper скорости чувствительное приложение, это не должно быть проблемой. Дополнительная ясность, которую Вы получите от использования интерфейса обычно, восполняет любое воспринятое уменьшение скорости.

46
ответ дан 2 revs 12 November 2019 в 10:03
поделиться

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

0
ответ дан Mike Dunlavey 12 November 2019 в 10:03
поделиться

Да, существует штраф. Что-то, что может улучшить производительность относительно Вашей платформы, должно использовать неабстрактный класс без виртуальных функций. Тогда используйте указатель функции членства на свою невиртуальную функцию.

0
ответ дан 12 November 2019 в 10:03
поделиться

Да, но ничто примечательное к моему знанию. Хит производительности из-за 'косвенности', которую Вы имеете в каждом вызове метода.

Однако это действительно зависит от компилятора, который Вы используете, так как некоторые компиляторы не в состоянии встроить вызовы метода в классах, наследовавшихся абстрактному базовому классу.

, Если Вы хотите быть уверенными, что необходимо запустить собственные тесты.

0
ответ дан mortenbpost 12 November 2019 в 10:03
поделиться

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

0
ответ дан radu_c 12 November 2019 в 10:03
поделиться

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

Однако, это - плохая причина завинтить дизайн. При необходимости в большем количестве производительности используйте более быстрый сервер.

0
ответ дан jan.vdbergh 12 November 2019 в 10:03
поделиться

Единственное основное различие, о котором я знаю, - то, что, так как Вы не используете реальный класс, встраивание (очень?) тяжелее, чтобы сделать.

0
ответ дан Chris Jester-Young 12 November 2019 в 10:03
поделиться

Обратите внимание, что множественное наследование чрезмерно увеличивает размер экземпляра объекта с несколькими vtable указателями. С G ++ на x86, если Ваш класс имеет виртуальный метод и никакой базовый класс, у Вас есть один указатель на vtable. Если у Вас есть один базовый класс с виртуальными методами, у Вас все еще есть один указатель на vtable. Если у Вас есть два базовых класса с виртуальными методами, Вы имеете два vtable указатели на каждом экземпляре .

Таким образом, со множественным наследованием (который является тем, что реализация интерфейсов в C++), Вы платите размер указателя времен базовых классов в размере экземпляра объекта. Увеличение объема потребляемой памяти может иметь косвенные последствия производительности.

2
ответ дан hsivonen 12 November 2019 в 10:03
поделиться

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

0
ответ дан Simon Steele 12 November 2019 в 10:03
поделиться

Большинство людей отмечает штраф во время выполнения, и справедливо так.

Однако, по моему опыту, работа над крупными проектами, преимуществами от ясных интерфейсов и надлежащей инкапсуляции быстро сместила усиление в скорости. Модульный код может быть подкачан для улучшенной реализации, таким образом, конечным результатом является большое усиление.

Ваш пробег может варьироваться, и он ясно зависит от приложения, которое Вы разрабатываете.

3
ответ дан rlerallut 12 November 2019 в 10:03
поделиться

Я не думаю, что сравнение стоимости между вызовом виртуальной функции и прямым вызовом функции. Если Вы думаете об использовании абстрактного базового класса (интерфейс), то у Вас есть ситуация, где Вы хотите выполнить одно из нескольких действий, базирующихся динамического типа объекта. Необходимо сделать тот выбор так или иначе. Одна опция состоит в том, чтобы использовать виртуальные функции. Другой - переключатель на типе объекта, или через (потенциально дорогой) RTTI, или через добавление типа () метод к базовому классу (потенциально увеличивающий использование памяти каждого объекта). Таким образом, стоимость вызова виртуальной функции должна сравниться со стоимостью альтернативы, не к стоимости выполнения ничего.

3
ответ дан KeithB 12 November 2019 в 10:03
поделиться

Другая альтернатива, которая применима в некоторых случаях, является полиморфизмом времени компиляции с шаблонами. Полезно, например, когда Вы хотите сделать выбор реализации в начале программы, и затем использовать ее на время выполнения. Пример с полиморфизмом во время выполнения

class AbstractAlgo
{
    virtual int func();
};

class Algo1 : public AbstractAlgo
{
    virtual int func();
};

class Algo2 : public AbstractAlgo
{
    virtual int func();
};

void compute(AbstractAlgo* algo)
{
      // Use algo many times, paying virtual function cost each time

}   

int main()
{
    int which;
     AbstractAlgo* algo;

    // read which from config file
    if (which == 1)
       algo = new Algo1();
    else
       algo = new Algo2();
    compute(algo);
}

тот же полиморфизм времени компиляции использования

class Algo1
{
    int func();
};

class Algo2
{
    int func();
};


template<class ALGO>  void compute()
{
    ALGO algo;
      // Use algo many times.  No virtual function cost, and func() may be inlined.
}   

int main()
{
    int which;
    // read which from config file
    if (which == 1)
       compute<Algo1>();
    else
       compute<Algo2>();
}
4
ответ дан KeithB 12 November 2019 в 10:03
поделиться

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

кроме того, при использовании виртуальной функции компилятор не может встроить вызов функции. Поэтому мог быть штраф использованию виртуальной функции для некоторых небольших функций. Это обычно - самый большой "хит" производительности, который Вы, вероятно, будете видеть. Это действительно только проблема, если функция является небольшой и названа много раз, говорят из цикла.

5
ответ дан David Dibben 12 November 2019 в 10:03
поделиться

Существует маленький штраф на вызов виртуальной функции по сравнению с регулярным вызовом. Вы вряд ли будете наблюдать различие, если Вы не сделаете сотни тысяч вызовов в секунду, и цену часто стоит заплатить за добавленную ясность кода так или иначе.

9
ответ дан moonshadow 12 November 2019 в 10:03
поделиться

Функции, вызванные с помощью виртуальной отправки, не встраиваются

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

стоимость Виртуального вызова зависит от платформы

Что касается вызова служебный штраф по сравнению с нормальным вызовом функции, ответ зависит от Вашей целевой платформы. Если Ваш предназначаются для ПК с x86/x64 ЦП, штраф за то, что вызвали виртуальную функцию является очень маленьким, поскольку современный x86/x64 ЦП может выполнить предсказание ветвлений на непрямых вызовах. Однако при предназначении для PowerPC или некоторой другой платформы RISC штраф виртуального вызова может быть довольно значительным, потому что непрямые вызовы никогда не предсказываются на некоторых платформах (Cf. ПК/Xbox 360 Лучших практик Кросс-платформенной разработки ).

24
ответ дан Suma 12 November 2019 в 10:03
поделиться

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

2
ответ дан yrp 12 November 2019 в 10:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: