Я знаю, что встроенный подсказка или запрос к компилятору и его используемому для предотвращения издержек вызова функции.
Таким образом на том, какое основание можно определить, является ли функция кандидатом на встраивание или нет? В этом случае нужно постараться не встраивать?
Избежать затрат на вызов функции - это только половина дела.
do:
inline
вместо #define
inline
: более быстрый код и меньшие исполняемые файлы (подробнее шансы остаться в кеше кода) не:
при разработке библиотеки, чтобы сделать класс расширяемым в будущем вам следует:
Помните, что ключевое слово inline
является подсказкой для компилятора: компилятор может решить не встраивать функцию, и он может решить встроить функции, которые не были отмечены inline
в первое место. Я обычно избегаю отмечать функцию встроенной
(кроме, может быть, при написании очень-очень маленьких функций).
Что касается производительности, мудрым подходом является (как всегда) профилирование приложения, а затем, в конечном итоге, встроенный
набор функций, представляющих узкое место.
Ссылки:
РЕДАКТИРОВАТЬ: Бьярн Страуструп, C ++ Язык программирования:
Функция может быть определена как
встроенная
. Например:
inline int fac(int n)
{
return (n < 2) ? 1 : n * fac(n-1);
}
Спецификатор
inline
- это подсказка компилятору, что он должен попытаться сгенерировать код для вызоваfac ()
inline вместо того, чтобы устанавливать код для функция один раз, а затем вызов через обычный механизм вызова функции. Умный компилятор может сгенерировать константу720
для вызоваfac (6)
. Возможность взаимно рекурсивных встроенных функций, встроенных функций, которые рекурсивны или не рекурсивны в зависимости от ввода, и т. Д. Делает невозможным гарантировать, что каждый вызоввстроенной
функции фактически встроен. Степень продуманности компилятора не может быть законодательно закреплена, поэтому один компилятор может генерировать720
, другой6 * fac (5)
, а третий - вызов без встроенного кодаfac (6)
.Чтобы сделать встраивание возможным при отсутствии необычно умных средств компиляции и компоновки, определение - а не просто объявление - встроенной функции должно быть в области видимости (§9.2). Встроенный спецификатор
не влияет на семантику функции. В частности, встроенная функция по-прежнему имеет уникальный адрес и, следовательно, имеет
статические
переменные (§7.1.2) встроенной функции.
EDIT2: ISO-IEC 14882-1998, 7.1.2 Спецификаторы функций
Объявление функции (8.3.5, 9.3, 11.4) со встроенным спецификатором
объявляет встроенную функцию. Встроенный спецификатор указывает реализации, что встроенная подстановка тела функции в точке вызова предпочтительнее обычного механизма вызова функции. Реализация не требуется для выполнения этой встроенной замены в точке вызова; однако, даже если эта встроенная подстановка опущена, другие правила для встроенных функций, определенных в 7.1.2, все равно должны соблюдаться.
Кроме того, встроенный метод имеет серьезные побочные эффекты при сопровождении больших проектов. Когда встроенный код изменяется, все файлы, которые его используют, будут автоматически перестроены компилятором (это хороший компилятор). Это может отнять у вас много времени на разработку.
Когда встроенный
метод передается в исходный файл и больше не встраивается, весь проект должен быть перекомпонован (по крайней мере, таков мой опыт). А также при преобразовании методов во встроенные.
inline
has very little to do with optimization. inline
is an instruction to the compiler not to produce an error if the function given definition occurs multiple times in the program and a promise that the definition will occur in every translation that it is used and everywhere it does appear it will have exactly the same definition.
Given the above rules, inline
is suitable for short functions whose body doesn't necessitate including extra dependencies over what just a declaration would need. Every time the defintion is encountered it must be parsed and code for its body may be generated so it implies some compiler overhead over a function defined only once in a single source file.
A compiler may inline (i.e. replace a call to the function with code that performs that action of that function) any function call that it chooses. It used to be the case that it "obviously" couldn't inline a function that wasn't declared in the same translation unit as the call but with the increasing use of link time optimization even this isn't true now. Equally true is the fact that functions marked inline
may not be inlined.
Указание компилятору встроить функцию - это оптимизация, и самое важное правило оптимизации состоит в том, что преждевременная оптимизация - это корень всех зол. Всегда пишите четкий код (используя эффективные алгоритмы), затем профилируйте свою программу и оптимизируйте только те функции, которые занимают слишком много времени.
Если вы обнаружите, что конкретная функция очень короткая и простая, и ее вызывают десятки тысяч раз в жесткий внутренний цикл, это может быть хорошим кандидатом.
Однако вы можете быть удивлены - многие компиляторы C ++ автоматически встраивают небольшие функции для вас - и они также могут игнорировать ваш запрос на встраивание.
Преждевременная оптимизация - корень всех зол!
Как правило, я обычно встраиваю только «геттеры» и «сеттеры». После того, как код заработает и станет стабильным, профилирование может показать, какие функции могут выиграть от встраивания.
С другой стороны, большинство современных компиляторов имеют неплохие алгоритмы оптимизации и будут встраивать то, что вы должны были встроить за вас.
Повторное предположение - напишите встроенные однострочные функции и подумайте о других позже.
Встроенные функции могут улучшить производительность вашего кода, устраняя необходимость помещать аргументы в стек. если рассматриваемая функция находится в критической части вашего кода, вы должны принять встроенное решение, а не встроенное в оптимизирующую часть вашего проекта,
вы можете узнать больше о встроенных функциях в c ++ faq
Лучший способ узнать это - профилировать свою программу и отмечать небольшие функции, которые вызываются много раз и прожигают циклы ЦП как inline
. Ключевое слово здесь "small" - как только накладные расходы на вызов функции незначительны по сравнению с временем, потраченным на функцию, бессмысленно встраивать их.
Я бы предложил другое использование, если у вас есть небольшие функции, которые получают вызывается в критически важном для производительности коде достаточно часто, чтобы сделать актуальным промах в кэше, вам, вероятно, следует также встроить их. Опять же, это то, что профилировщик должен вам сказать.
Я часто использую встроенные функции не для оптимизации, а для того, чтобы сделать код более читабельным. Иногда сам код короче и легче для понимания, чем комментарии, описательные имена и т. Д. Например:
void IncreaseCount() { freeInstancesCnt++; }
Читатель сразу знает полную семантику кода.
Я обычно следую правилу большого пальца, когда делаю функцию с 3-4 простыми операторами как встроенными. Но следует помнить, что это всего лишь подсказка для компилятора. Последний вызов, чтобы сделать его встроенным или нет, принимает только компилятор. Если операторов больше, чем этих, я не буду объявлять встроенными, так как в случае с глупым компилятором это может привести к раздуванию кода.
Лучшим способом было бы изучить и сравнить сгенерированные инструкции для встроенных и не встроенных. Однако всегда можно безопасно опустить inline
. Использование в строке
может привести к нежелательным неприятностям.
Решая, использовать ли inline, я обычно держу в уме следующую идею: на современных машинах задержка памяти может быть более узким местом, чем необработанные вычисления. Известно, что встраивание часто вызываемых функций увеличивает размер исполняемого файла. Кроме того, такая функция может быть сохранена в кэше кода ЦП, что уменьшит количество промахов в кэше, когда к этому коду потребуется доступ.
Следовательно, вы должны решить для себя: увеличивает или уменьшает встраивание размер сгенерированного машинного кода? Насколько вероятно, что вызов функции вызовет промах в кеше? Если он пропитан по всему коду, тогда я бы сказал, что вероятность высока. Если он ограничен одним узким циклом, то вероятность, надеюсь, мала.
Я обычно использую встраивание в случаях, которые я перечисляю ниже. Однако если вас действительно беспокоит производительность, важно профилирование. Кроме того, вы можете проверить, действительно ли компилятор принимает подсказку.