it-swarm.com.ru

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

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

248
Lennie De Villiers

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

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

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

Я мог видеть ситуацию, подобную этой, имеющую заметную разницу:

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);
138
Brian R. Bondy

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

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

Недостатки

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

Магия

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

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

В современном C++ 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

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

41
Emilio Garavaglia

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

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

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

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

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

16
paxdiablo

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

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

  1. Это не требует служебных вызовов.

  2. Это также экономит накладные расходы на переменные Push/Pop в стеке при вызове функции.

  3. Это также экономит накладные расходы на обратный вызов из функции.

  4. Это увеличивает местность ссылки, используя кэш инструкций.

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

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

12
TSS

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

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

6
doc

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

4
Devrin

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

4
Ferruccio

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

3
J.M. Stoorvogel

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

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

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

3
Tall Jeff

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

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

1
HumbleWebDev

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

1
Martin Wilde

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

1
mehrdad zomorodian