c++ votes Когда использовать встроенную функцию и когда ее не использовать?




rs add force (11)

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

Я знаю, что inline является подсказкой или запросом к компилятору и используется для предотвращения накладных расходов на вызовы функций.

Итак, на каком основании можно определить, является ли функция кандидатом для встраивания или нет? В таком случае следует избегать встраивания?


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


Я прочитал несколько ответов и вижу, что некоторые вещи отсутствуют.

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

Компиляторы достаточно умны, а короткие функции всегда делают встроенным. И никогда не делает длинную функцию встроенной, если программист не сказал это сделать.

Я знаю, что inline - это подсказка или запрос на компилятор

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

Так когда использовать inline ?

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

Например, у меня есть эта функция:

inline bool ValidUser(const std::string& username, const std::string& password)
{
    //here it is quite long function
}

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


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

вы можете больше узнать о inline в c ++ faq


Избежание стоимости вызова функции - это всего лишь половина истории.

делать:

  • используйте inline вместо #define
  • очень маленькие функции - хорошие кандидаты для inline : более быстрый код и меньшие исполняемые файлы (больше шансов остаться в кеше кода)
  • функция мала и называется очень часто

нет:

  • большие функции: приводит к большему количеству исполняемых файлов, что значительно снижает производительность независимо от более быстрого выполнения, которое возникает из-за накладных расходов
  • встроенные функции, которые связаны с I / O
  • функция используется редко
  • конструкторы и деструкторы: даже когда пустой, компилятор генерирует для них код
  • бинарная совместимость при разработке библиотек:
    • встроить существующую функцию
    • изменить встроенную функцию или сделать встроенную функцию non-inline: предыдущая версия библиотеки вызывает старую реализацию

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

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

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

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

Рекомендации:

EDIT: Bjarne Stroustrup, язык программирования C ++:

Функция может быть определена как inline . Например:

inline int fac(int n)
{
  return (n < 2) ? 1 : n * fac(n-1);
}

Спецификатор inline является подсказкой для компилятора, что он должен попытаться сгенерировать код для вызова функции fac() inline, вместо того, чтобы однажды разложить код для функции, а затем вызвать обычный механизм вызова функции. Умный компилятор может генерировать константу 720 для функции вызова fac(6) . Возможность взаимно рекурсивных встроенных функций, встроенных функций, которые рекурсируют или не зависят от ввода и т. Д., Не позволяет гарантировать, что каждый вызов inline функции фактически встроен. Степень умения компилятора не может быть законодательно закреплена, поэтому один компилятор может генерировать 720 , еще один 6 * fac(5) и еще один необязательный факс fac(6) .

Чтобы сделать возможной инкрустацию в отсутствие необычно умных средств компиляции и компоновки, определение, а не просто объявление встроенной функции должно быть в области (§9.2). Встроенный especifier не влияет на семантику функции. В частности, встроенная функция все еще имеет уникальный адрес и поэтому имеет static переменные (§7.1.2) встроенной функции.

EDIT2: ISO-IEC 14882-1998, 7.1.2 Спецификаторы функций

Объявление функции (8.3.5, 9.3, 11.4) с inline спецификатором объявляет встроенную функцию. Спецификатор inline указывает на реализацию, что встроенная подстановка тела функции в точке вызова предпочтительнее обычного механизма вызова функции. Реализация не требуется для выполнения этой встроенной подстановки в точке вызова; однако, даже если эта встроенная замена опущена, другие правила для встроенных функций, определенных в 7.1.2, все равно должны соблюдаться.


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

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

Тем не менее, вы можете быть удивлены - многие компиляторы C ++ автоматически встраивают в вас небольшие функции, и они могут также игнорировать ваш запрос на inline.


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

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

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

  • Короткие подпрограммы, вызываемые в замкнутом цикле.
  • Очень базовые функции доступа (get / set) и функции обертки.
  • Код шаблона в файлах заголовков, к сожалению, автоматически получает встроенный намек.
  • Коротко код, который используется как макрос. (Например, min () / max ())
  • Краткие математические процедуры.

Преждевременная оптимизация - это корень всех злых!

Как правило, я обычно устанавливаю только «геттеры» и «сеттеры». Как только код работает и стабилен, профилирование может показать, какие функции могут извлечь выгоду из вложения.

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

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


Я часто использую встроенные функции не как оптимизацию, а чтобы сделать код более удобочитаемым. Иногда сам код короче и легче понять, чем комментарии, описательные имена и т. Д. Например:

void IncreaseCount() { freeInstancesCnt++; }

Читатель сразу знает полную семантику кода.


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

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

Компилятор может встроить (т. Е. Заменить вызов функции кодом, который выполняет это действие этой функции) любой вызов функции, который он выбирает. Раньше это было так, что «очевидно» не могло встроить функцию, которая не была объявлена ​​в той же самой системе перевода, что и вызов, но с увеличением использования оптимизации времени ссылки, даже это сейчас не так. Не менее верно тот факт, что функции, отмеченные inline могут не быть вложенными.


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

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





inline