Я знаю, что inline - это подсказка или запрос компилятору, и он используется, чтобы избежать накладных расходов на вызовы функций.
Итак, на каком основании можно определить, является ли функция кандидатом на встраивание или нет? В каком случае следует избегать встраивания?
inline
для новичка в C ++ тоCFLAGS
же, что для новичка в Gentoo: нет, компиляция с ним-O3 -funroll-loops -finline-functions
не заставит ваш старый Pentium летать;)Ответы:
Избежать затрат на вызов функции - это только половина дела.
делать:
inline
вместо#define
inline
: более быстрого кода и меньших исполняемых файлов (больше шансов остаться в кеше кода)нет:
при разработке библиотеки, чтобы сделать класс расширяемым в будущем, вы должны:
Помните, что
inline
ключевое слово является подсказкой для компилятора: компилятор может решить не встроить функцию, и он может решить встроить функции, которые не были отмеченыinline
в первую очередь. Я вообще избегаю маркировкиinline
(возможно, когда пишу очень маленькие функции).Что касается производительности, мудрый подход (как всегда) заключается в профилировании приложения, а затем в конечном итоге
inline
набора функций, представляющих узкое место.Ссылки:
РЕДАКТИРОВАТЬ: Бьярне Страуструп, Язык программирования C ++:
EDIT2: ISO-IEC 14882-1998, 7.1.2 Спецификаторы функций
источник
inline
это гораздо больше, чем подсказка компилятору. Это изменяет языковые правила о нескольких определениях. Кроме того, наличие статических данных не является чугунной причиной, чтобы избежать встраивания функции. Реализация обязана выделять один статический объект для каждой статической функции независимо от того, объявлена функцияinline
или нет. Классы все еще расширяемы, если у них есть встроенные конструкторы и виртуальные деструкторы. И пустой деструктор фигурной скобки - это единственная виртуальная функция, которую иногда стоит оставить в строке.inline
, то результат заключается в том, что функция не становится встроенной: вы платите цену за вызов, а также каждая единица перевода, которая включает и вызывает функцию, получает собственную копию кода и статических переменных. Причиной отказа от использования конструкторов и деструкторов при разработке библиотеки является двоичная совместимость с будущими версиями вашей библиотекиinline
функции могут быть встроены, если компилятор чувствует себя так. Иinline
функции не будут встроены, если компилятор решит не включать их. Как сказал Чарльз Бейли, это меняет языковые правила. Вместо того, чтобы думать об этом как о подсказке по оптимизации, более правильно думать об этом как о совершенно другой концепции.inline
Ключевое слово указывает компилятору разрешить несколько определений, и больше ничего. Оптимизация «встраивания» может применяться практически к любой функции, независимо от того, помечена она или нетinline
.inline
для того, чтобы получить встраивание функций. Иногда нам нужны другие преимущества, такие как обход ODR.inline
имеет очень мало общего с оптимизацией.inline
является инструкцией для компилятора не выдавать ошибку, если заданное определение функции встречается в программе несколько раз, и обещание, что определение будет появляться в каждом используемом им переводе и везде, где оно появляется, будет иметь точно такое же определение.Учитывая вышеприведенные правила,
inline
подходит для коротких функций, в теле которых нет необходимости включать дополнительные зависимости от того, что понадобится только для объявления. Каждый раз, когда определение встречается, оно должно быть проанализировано, и может быть сгенерирован код для его тела, так что это подразумевает некоторые накладные расходы компилятора на функцию, определенную только один раз в одном исходном файле.Компилятор может встроить (т.е. заменить вызов функции кодом, выполняющим это действие этой функции) любой вызов функции, который он выберет. Раньше было так, что «очевидно» не могло встроить функцию, которая не была объявлена в том же модуле трансляции, что и вызов, но с растущим использованием оптимизации времени соединения, даже сейчас это не так. В равной степени верно и то, что отмеченные функции
inline
не могут быть встроенными.источник
inline
ключевым словом? И что такое счастливое совпадение?Указание компилятору встроить функцию - это оптимизация, и самое важное правило оптимизации заключается в том, что преждевременная оптимизация является корнем всего зла. Всегда пишите чистый код (используя эффективные алгоритмы), затем профилируйте свою программу и оптимизируйте только те функции, которые занимают слишком много времени.
Если вы обнаружите, что конкретная функция очень коротка и проста, и она вызывается десятки тысяч раз в тесном внутреннем цикле, это может быть хорошим кандидатом.
Однако вы можете быть удивлены - многие компиляторы C ++ автоматически встроат для вас небольшие функции - и они могут также игнорировать ваш запрос на встроенные функции.
источник
/FAcs
в Visual Studio,-s
в GCC), чтобы увидеть, что именно он делает. По моему опыту, оба этих компилятора довольно сильно взвешивают встроенное ключевое слово.inline
вообще не взвешивают ключевые слова. То есть, если вы видите встроенную функцию и удаляетеinline
из нее спецификатор, она все равно будет встроенной. Если у вас есть конкретные примеры обратного, поделитесь ими!inline
ключевое слово мешает "очистить код"? Ключевое слово в «преждевременной оптимизации» является преждевременным , а не оптимизацией. Сказать, что вы должны активно * избегать оптимизаций - это просто мусор. Смысл этой цитаты заключается в том, что вам следует избегать оптимизаций, которые могут не потребоваться, и иметь вредные побочные эффекты для кода (например, сделать его менее обслуживаемым). Я не вижу, какinline
ключевое слово сделает код менее понятным или как может быть вредно добавлять его в функцию.Лучший способ выяснить это - профилировать вашу программу и пометить небольшие функции, которые вызываются много раз и прожигать циклы ЦП
inline
. Ключевое слово здесь - «маленький» - как только издержки вызова функции незначительны по сравнению с временем, потраченным на функцию, бессмысленно их включать.Еще одно использование, которое я бы предложил, если у вас есть небольшие функции, которые вызываются в критичном к производительности коде достаточно часто, чтобы сделать кэш-память релевантной, вам, вероятно, следует также включить их. Опять же, это то, что профилировщик должен быть в состоянии сказать вам.
источник
Преждевременная оптимизация - корень всего зла!
Как правило, я обычно включаю только «получатели» и «установщики». Как только код заработает и станет стабильным, профилирование может показать, какие функции могут извлечь выгоду из встраивания.
С другой стороны, большинство современных компиляторов имеют неплохие алгоритмы оптимизации и встраивают то, что вы должны были указать для себя.
Повторное использование - напишите встроенные однострочные функции, а потом позаботьтесь о других.
источник
Встроенные функции могут улучшить производительность вашего кода, устраняя необходимость помещать аргументы в стек. если рассматриваемая функция находится в критической части вашего кода, вы должны принять встроенное, а не встроенное решение в части оптимизации вашего проекта,
Вы можете прочитать больше о inline в faq c ++
источник
Я часто использую встроенные функции не для оптимизации, а для того, чтобы сделать код более читабельным. Иногда сам код короче и его легче понять, чем комментарии, описательные имена и т. Д. Например:
Читатель сразу знает полную семантику кода.
источник
Я обычно следую правилу большого пальца, где я делаю функцию с 3-4 простыми утверждениями как встроенными. Но хорошо помнить, что это всего лишь подсказка компилятору. Последний вызов, чтобы сделать его встроенным или нет, принимается только компилятором. Если их будет больше, чем много, я не буду объявлять их как встроенные, так как с тупым компилятором это может привести к раздуванию кода.
источник
Лучшим способом было бы изучить и сравнить сгенерированные инструкции для встроенных и не встроенных. Тем не менее, это всегда безопасно опустить
inline
. Использованиеinline
может привести к неприятностям, которые вам не нужны.источник
Принимая решение о том, использовать ли inline, я обычно имею в виду следующую идею: на современных машинах задержка памяти может быть более узким местом, чем необработанные вычисления. Известно, что часто вызываемые встроенные функции увеличивают размер исполняемого файла. Кроме того, такая функция может быть сохранена в кеше кода ЦП, что уменьшит количество пропусков кеша, когда к этому коду необходимо получить доступ.
Следовательно, вы должны решить для себя: увеличивает или уменьшает встроенный размер генерируемого машинного кода? Насколько вероятно, что вызов функции приведет к отсутствию кэша? Если это будет распространено по всему коду, то я бы сказал, что вероятность высока. Если он ограничен одним узким контуром, то вероятность, надеюсь, низкая.
Я обычно использую встраивание в случаях, перечисленных ниже. Однако, если вы действительно обеспокоены производительностью, профилирование необходимо. Кроме того, вы можете проверить, действительно ли компилятор принимает подсказку.
источник
Кроме того, встроенный метод имеет серьезные побочные эффекты при ведении больших проектов. При изменении встроенного кода все файлы, которые его используют, будут автоматически перекомпилированы компилятором (если это хороший компилятор). Это может потратить много времени на разработку.
Когда
inline
метод переносится в исходный файл и больше не указывается, весь проект должен быть перестроен (по крайней мере, это был мой опыт). А также когда методы конвертируются во встроенные.источник
inline
или нет, не имеет значения (кроме как безinline
ключевого слова, вы получите ошибки компоновщика - ноinline
ключевое слово не является проблемой, вызывающей чрезмерное перестроение.Использовать встроенный классификатор функций следует только в том случае, если код функции небольшой. Если функции больше, следует отдавать предпочтение обычным функциям, поскольку экономия в памяти требует сравнительно небольшого снижения скорости выполнения.
источник
Когда вы думаете, что ваш код достаточно мал для использования в качестве встроенного, и помните, что встроенная функция дублирует ваш код и вставляет его при вызове функции, поэтому она может быть достаточно хороша для увеличения времени выполнения, но также и для увеличения потребления памяти. Вы не можете использовать встроенную функцию, когда используете циклическую / статическую переменную / рекурсивную / switch / goto / виртуальную функцию. Виртуальные средства ждут до времени выполнения, а встроенные - во время компиляции, поэтому их нельзя использовать одновременно.
источник
Я прочитал некоторые ответы и вижу, что некоторые вещи отсутствуют.
Правило, которое я использую, не должно использовать inline, если я не хочу, чтобы оно было встроенным. Выглядит глупо, теперь объяснение.
Компиляторы достаточно умны, а короткие функции всегда делают встроенными. И никогда не заставляет long работать как inline, если только программист не сказал, что это нужно.
На самом деле
inline
это заказ для компилятора, у него нет выбора, и послеinline
ключевого слова весь код встроен. Таким образом, вы никогда не сможете использоватьinline
ключевое слово, и компилятор разработает самый короткий код.Так когда же использовать
inline
?Использовать, если вы хотите иметь встроенный код. Я знаю только один пример, потому что я использую его только в одной ситуации. Это аутентификация пользователя.
Например, у меня есть эта функция:
Независимо от того, насколько велика эта функция, я хочу, чтобы она была встроенной, потому что это затрудняет взлом моего программного обеспечения.
источник