Накладные расходы на разыменование указателей и условные операторы - PullRequest
11 голосов
/ 19 сентября 2011

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

void my_loop_function(int dt) {
  if (conditionX && conditionY) 
    doFoo();
  else
    doBar();

  ...
}

Я привык использовать указатель на функцию, которая указывает на определенную логическую функцию, соответствующую текущему состоянию персонажа , например:

void (*updater)(int);

void something_happens() {
  updater = &doFoo;
}
void something_else_happens() {
  updater = &doBar;
}
void my_loop_function(int dt) {
  (*updater)(dt);

  ...
}

И в случае, когда я не хочу ничего делать, я определяю фиктивную функцию и указываю на нее, когда мне нужно:

void do_nothing(int dt) { }

Теперь я действительно задаюсь вопросом:зацикливаться на этом без нужды?Приведенный выше пример, конечно, прост;иногда мне нужно проверять множество переменных, чтобы выяснить, какие части кода мне нужно выполнить, и поэтому я решил, что использование этих указателей на функцию «состояние» действительно будет более оптимальным, и, на мой взгляд, естественным, но несколько человек, которых яЯ имею дело с очень не согласен.

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

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

Спасибо

Ответы [ 5 ]

6 голосов
/ 19 сентября 2011

Подход с помощью указателя функции позволяет сделать переходы асинхронными. Вместо того, чтобы просто передать dt в updater, передайте и объект. Теперь программа обновления сама может отвечать за переходы между состояниями. Это локализует логику перехода состояний вместо глобализации в одной большой уродливой функции if ... else if ... else if ....

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

4 голосов
/ 19 сентября 2011

Я думаю, что я согласен с неверующими здесь. Вопрос денег в этом случае , как будет установлено значение указателя ?

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

Учтите, что на практике something_else_happens придется проверить предыдущее значение указателя, прежде чем устанавливать его на другое значение. То же самое относится и к something_different_happens и т. Д. Фактически вы повсеместно разбросали логику для своего конечного автомата и затруднили ее отслеживание.

2 голосов
/ 19 сентября 2011

Теперь, что мне действительно интересно, так это: я бесполезно зацикливаюсь на этом?

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

Херб Саттер и Андрей Александреску в Стандарты кодирования C ++: 101 правила, руководящие указания и передовой опыт посвятите этому главу 8 под названием «Не оптимизируйте преждевременно» , и они хорошо ее обобщают:

Шпора, а не охотничья лошадь (латинская пословица): преждевременная оптимизация вызывает привыкание и непродуктивность. Первое правило оптимизации: не делайте этого. Второе правило оптимизации (только для экспертов): пока не делайте этого. Измерьте дважды, оптимизируйте один раз.

Стоит также прочитать главу 9: «Не пессимизируйте преждевременно»

0 голосов
/ 19 сентября 2011

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

0 голосов
/ 19 сентября 2011

Проверка условия:

  • извлечение значения
  • сравнение (вычитание)
  • Переход, если ноль (или не ноль)

Выполните косвенное обращение:

  • Извлеките адрес
  • прыжок.

Может быть даже более производительным!

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

«Не используйте косвенное обращение / не используйте виртуальное / не используйте указатель на функцию / don»т динамический состав и т. д. "в большинстве случаев это просто мифы, основанные на исторических ограничениях ранних архитектур компиляторов и аппаратного обеспечения.

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