Преимущества встроенных функций в С++?

В чем преимущества/недостатки использования встроенных функций в С++? Я вижу, что он только увеличивает производительность для кода, который выдает компилятор, но с оптимизированными сегодня компиляторами, быстрыми процессорами, огромной памятью и т.д. (Не так, как в 1980 году, где памяти было мало, и все должно было соответствовать 100 КБ памяти), что преимущества у них действительно есть сегодня?

Ответ 1

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

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

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

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

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);

Ответ 2

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

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

Недостатки

  • Это может сделать ваш код более крупным (т.е. если вы используете встроенную функцию для нетривиальных функций). Таким образом, это может спровоцировать оптимизацию подкачки и поражений от компилятора.
  • Он слегка разбивает вашу инкапсуляцию, потому что она раскрывает внутреннюю часть вашей обработки объекта (но тогда и каждый член "private" тоже). Это означает, что вы не должны использовать вложение в шаблон PImpl.
  • Он слегка разбивает вашу инкапсуляцию. 2: С++ inlining разрешается во время компиляции. Это означает, что если вы измените код встроенной функции, вам нужно будет перекомпилировать весь код, используя его, чтобы быть уверенным, что он будет обновлен (по той же причине я избегаю значений по умолчанию для параметров функции).
  • При использовании в заголовке он делает ваш файл заголовка более крупным и, таким образом, разбавит интересную информацию (например, список методов класса) с кодом, на который пользователь не заботится (вот почему я объявляю inlined функции внутри класса, но определит его в заголовке после тела класса и никогда не будет внутри тела класса).

Вложение магии

  • Компилятор может или не может встроить функции, отмеченные как встроенные; он также может принять решение о встроенных функциях, не отмеченных как inline при компиляции или времени связывания.
  • Inline работает как копирование/вставка, контролируемая компилятором, что сильно отличается от макропроцессора: макрос будет принудительно встроен, загрязнит все пространства имен и код, не будет легко отлаживаться и будет сделайте это, даже если компилятор назвал бы его неэффективным.
  • Каждый метод класса, определенный внутри тела самого класса, считается "встроенным" (даже если компилятор все же может решить не встраивать его
  • Виртуальные методы не должны быть проницаемыми. Тем не менее, иногда, когда компилятор может точно знать тип объекта (т.е. Объект был объявлен и сконструирован внутри одного и того же тела функции), даже виртуальная функция будет встроена, потому что компилятор точно знает тип объекта.
  • Методы/функции шаблонов не всегда встроены (их присутствие в заголовке не сделает их автоматически встроенными).
  • Следующим шагом после "inline" является метапрограммирование шаблонов. То есть "Вставляя" свой код во время компиляции, иногда компилятор может вывести конечный результат функции... Поэтому сложный алгоритм иногда можно свести к выражению return 42 ;. Это для меня крайняя инкрустация. Это случается редко в реальной жизни, это делает время компиляции более длинным, не раздувает ваш код и сделает ваш код быстрее. Но, как и грааль, не пытайтесь применять его повсюду, потому что большая часть обработки не может быть решена таким образом... Тем не менее, это так здорово...
    :-p

Ответ 3

В архаичных C и С++ inline похож на register: предложение (не более чем предложение) компилятору о возможной оптимизации.

В современном С++ inline сообщает компоновщику, что если в разных единицах перевода обнаружено несколько определений (не деклараций), они все одинаковы, и компоновщик может свободно сохранить один и отбросить все остальные.

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

Функции-члены, определенные внутри класса, являются "встроенными" по умолчанию, как и функции шаблона (в отличие от глобальных функций).

//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }

//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }

//main.cpp
#include "fileA.h"
void acall();

int main()
{ 
   afunc(); 
   acall();
}

//output
this is afunc
this is afunc

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

Ответ 4

Вложение - это предложение компилятору, которое можно игнорировать. Он идеален для небольших бит кода.

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

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

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

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

Ответ 5

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

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

  • Это не требует служебных вызовов функций.

  • Он также сохраняет служебные данные переменных push/pop в стеке, а вызов функции.

  • Он также сохраняет накладные расходы на обратный вызов из функции.

  • Он увеличивает локальность ссылок, используя кэш команд.

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

Чтобы узнать больше об этом, вы можете перейти по этой ссылке http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html

Ответ 6

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

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

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

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

Ответ 10

Это не все о производительности. Оба С++ и C используются для встроенного программирования, сидящего поверх аппаратного обеспечения. Если вы, например, напишите обработчик прерываний, вам нужно убедиться, что код можно выполнить сразу, без добавления дополнительных регистров и/или страниц памяти. То есть, когда inline вам пригодится. Хорошие компиляторы делают некоторые "inlining" сами, когда требуется скорость, но "inline" заставляет их.

Ответ 11

Попал в ту же проблему с вложением функций в библиотеки. Кажется, что встроенные функции не компилируются в библиотеку. в результате компоновщик выдает ошибку "undefined reference", если исполняемый файл хочет использовать встроенную функцию библиотеки. (случилось с компиляцией Qt-источника с gcc 4.5.

Ответ 12

Почему бы не сделать все функции встроенными по умолчанию? Потому что это инженерный компромисс. Существует, по крайней мере, два типа "оптимизации": ускорение программы и уменьшение размера (объема памяти) программы. Вложение обычно ускоряет работу. Он избавляется от служебных функций вызова функции, избегая нажатия, а затем вытягивая параметры из стека. Тем не менее, это также увеличивает объем памяти в программе, поскольку каждый вызов функции теперь должен быть заменен полным кодом функции. Чтобы сделать вещи еще более сложными, помните, что в ЦП хранится часто используемые куски памяти в кеше на процессоре для сверхбыстрого доступа. Если вы сделаете изображение с программной памятью достаточно большим, ваша программа не сможет эффективно использовать кеш, а в худшем случае вложение может фактически замедлить работу вашей программы. В какой-то мере компилятор может рассчитать, что такое компромисс, и может ли он принимать более правильные решения, чем вы можете, просто глядя на исходный код.

Ответ 13

Наш профессор информатики призвал нас никогда не использовать встроенную программу С++. Когда его спросили, почему, он любезно объяснил, что современные компиляторы должны определить, когда использовать inline автоматически.

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

Ответ 14

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

Есть ли недостатки с встроенными функциями?

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

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

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

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

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

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