Преимущества подставляемых функций в C++?

253
задан 6 revs, 5 users 50% 19 February 2015 в 11:51
поделиться

7 ответов

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

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

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

я видел, что такая ситуация имела обнаруживаемое значение:

inline int aplusb_pow2(int a, int b) {
  return (a + b)*(a + b) ;
}

for(int a = 0; a < 900000; ++a)
    for(int b = 0; b < 900000; ++b)
        aplusb_pow2(a, b);
141
ответ дан 4 revs 23 November 2019 в 02:51
поделиться

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

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

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

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

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

16
ответ дан 2 revs 23 November 2019 в 02:51
поделиться

Преимущества

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

Недостатки

  • , Это может сделать код больше (т.е. если Вы используете встроенный для нетривиальных функций). По сути, это могло вызвать подкачку страниц и победить оптимизацию из компилятора.
  • Это немного повреждает Вашу инкапсуляцию, потому что это представляет внутреннюю из Вашей обработки объекта (но тогда, каждый "частный" участник был бы, также). Это означает, что Вы не должны использовать встраивание в шаблоне PImpl.
  • Это немного повреждает Вашу инкапсуляцию 2: встраивание C++ разрешено во время компиляции. Что означает, что это должно Вы изменять код встроенной функции, необходимо было бы перекомпилировать весь код с помощью него, чтобы быть уверенными, что это будет обновлено (по той же причине, я избегаю значений по умолчанию для параметров функции)
  • , Когда используется в заголовке, это делает заголовочный файл больше, и таким образом, растворит интересную информацию (как список методы класса) с кодом, о котором пользователь не заботится о (это - причина, что я объявляю встроенные функции в классе, но определю его в заголовке после тела класса, и никогда в теле класса).

Волшебство Встраивания

  • компилятор может или не может встроить функции, которые Вы отметили как встроенные; это может также решить к подставляемым функциям, не отмеченным как встроенное при компиляции или соединении времени.
  • Встроенные работы как скопировать/вставить управляемый компилятором, который очень отличается от макроса препроцессора: макрос будет насильственно встроен, загрязнит все пространства имен и кодирует, не будет легко debuggable, и будет сделан, даже если компилятор управлял бы им как неэффективным.
  • Каждый метод класса, определенного в теле самого класса, рассматривают, как "встроено" (даже если компилятор может все еще решить не встроить его
  • , Виртуальные методы, как предполагается, не inlinable. Однако, иногда, когда компилятор может знать наверняка тип объекта (т.е. объект был объявлен и создан в том же теле функции), даже виртуальная функция будет встроена, потому что компилятор знает точно тип объекта.
  • Шаблонные методы/функции не всегда встраиваются (их присутствие в заголовке не заставит их автоматически встроить).
  • следующий шаг после "встроенный" является шаблонным метапрограммированием. Т.е. Путем "встраивания" кода во время компиляции, иногда, компилятор может вывести конечный результат функции... Таким образом, сложный алгоритм может иногда уменьшаться до своего рода return 42 ; оператор. Это для меня экстремальное значение, встраивающее . Это редко происходит в реальной жизни, это делает время компиляции дольше, не чрезмерно увеличит размер Вашего кода и сделает Ваш код быстрее. Но как чаша Грааля, не пытайтесь применить его везде, потому что большая часть обработки не может быть разрешена этот путь... Однако, это прохладно так или иначе...
    :-p
196
ответ дан 2 revs, 2 users 95% 23 November 2019 в 02:51
поделиться

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

4
ответ дан Devrin 23 November 2019 в 02:51
поделиться

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

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

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

3
ответ дан Tall Jeff 23 November 2019 в 02:51
поделиться

Заключение от другое обсуждение здесь:

там какие-либо недостатки с подставляемыми функциями?

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

, Но стоит отметить следующие моменты!

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

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

  • существует немного ситуаций, где подставляемая функция не может работать:

    • Для функции, возвращая значения; если оператор возврата существует.
    • Для функции, не возвращающей значений; если цикл, оператор переключения или оператор перехода существуют.
    • , Если функция является рекурсивной. - Источник
  • __inline ключевое слово заставляет функцию быть встроенной, только если Вы определяете оптимизировать опцию. Если оптимизируют, определяется, соблюдается ли __inline, зависит от установки встроенной опции оптимизатора. По умолчанию встроенная опция состоит в действительности в том каждый раз, когда оптимизатор выполняется. Если Вы определяете, оптимизируют, необходимо также определить noinline опцию, если Вы хотите __inline ключевое слово быть проигнорированными. - Источник

-1
ответ дан 2 revs 23 November 2019 в 02:51
поделиться

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

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

6
ответ дан 23 November 2019 в 02:51
поделиться
Другие вопросы по тегам:

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