Когда я должен написать ключевое слово "inline" для функции/метода?
когда я должен написать ключевое слово inline
для функции/метода в C++?
после просмотра некоторых ответов, некоторые связанные вопросы:
когда я не напишите ключевое слово "inline" для функции/метода в C++?
когда компилятор не будет знать, когда сделать функцию / метод "inline"?
имеет ли значение, если приложение многопоточный когда один пишет 'inline' для функции / метода?
12 ответов
Ох, одна из моих любимых мозолей.
inline
больше нравится static
или extern
чем директива, сообщающая компилятору встроить ваши функции. extern
, static
, inline
директивы связывания, использовали почти исключительно линкер, а не компилятор.
говорят, что inline
указывает компилятору, что вы считаете, что функция должна быть встроена. Возможно, это было верно в 1998 году, но десять лет спустя компилятор не нуждается в таких подсказках. Не упоминать люди обычно ошибаются, когда дело доходит до оптимизации кода, поэтому большинство компиляторов игнорируют "подсказку".
static
- имя переменной/функции не может использоваться в других единицах перевода. Компоновщику необходимо убедиться, что он случайно не использует статически определенную переменную/функцию из другой единицы перевода.extern
- используйте это имя переменной / функции в этом блоке перевода, но не жалуйтесь, если это не определено. Компоновщик отсортирует его и убедится, что весь код, который пытался использовать какой-то символ extern, имеет свой адрес.inline
- эта функция будет определена в нескольких единицах перевода, не беспокойтесь об этом. Компоновщику необходимо убедиться, что все единицы перевода используют один экземпляр переменной/функции.
Примечание: как правило, объявление шаблонов inline
is бессмысленно, поскольку они имеют семантику связи inline
уже. Однако,explicit
специализация и создание экземпляров шаблонов требуются inline
использовать.
конкретные ответы на ваши вопросы:
-
когда я должен написать ключевое слово "inline" для функции/метода в C++?
только если вы хотите, чтобы функция была определена в заголовке. Точнее, только когда функция определение может отображаться в нескольких единицах трансляции. Рекомендуется определить небольшие (как в одной строке) функции в заголовочном файле, так как это дает компилятору больше информации для работы при оптимизации кода. Это также увеличивает время компиляции.
-
когда я не должен писать ключевое слово "inline" для функции/метода в C++?
не добавляйте inline только потому, что вы думаете, что ваш код будет работать быстрее, если компилятор inlines он.
-
когда компилятор не будет знать, когда сделать функцию / метод "inline"?
как правило, компилятор сможет сделать это лучше, чем вы. Однако компилятор не имеет возможности встроенного кода, если он не имеет определения функции. В максимально оптимизированном коде обычно все
private
методы встроены независимо от того, просите вы об этом или нет.как в сторону, чтобы предотвратить встраивание в GCC, используйте
__attribute__(( noinline ))
, а в Visual Studio используйте__declspec(noinline)
. -
имеет ли значение, является ли приложение многопоточным, когда он пишет "inline" для функции/метода?
многопоточность никак не влияет на встраивание.
я хотел бы внести свой вклад во все великие ответы в этой теме с убедительным примером, чтобы рассеять любое оставшееся недоразумение.
учитывая два исходных файла, такие как:
-
inline111.cpp:
#include <iostream> void bar(); inline int fun() { return 111; } int main() { std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun; bar(); }
-
inline222.cpp:
#include <iostream> inline int fun() { return 222; } void bar() { std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun; }
-
случае A:
Compile:
g++ -std=c++11 inline111.cpp inline222.cpp
выход:
inline111: fun() = 111, &fun = 0x4029a0 inline222: fun() = 111, &fun = 0x4029a0
Обсуждение:
даже ты должен иметь идентичные определения вашего встроенного функции, компилятор C++ не флаг это, если это не так (на самом деле, из-за раздельной компиляции у него нет способа проверить это). Ваша собственная обязанность обеспечить это!
Линкер не жалуется на Одно Правило Определения, as
fun()
объявленinline
. Однако, потому что inline111.cpp является первой единицей перевода (которая фактически вызываетfun()
) обработанный компилятором, компилятор создает экземплярfun()
по его первый вызов-встреча в inline111.cpp. Если компилятор решит не расширенияfun()
на его призыв где-либо еще в вашей программе (например с inline222.cpp), вызовfun()
всегда будет связан с его экземпляром, созданным из inline111.cpp (вызовfun()
внутри inline222.cpp может также создать экземпляр в этой единице перевода,но он останется несвязанным). Действительно, это видно из тождественного&fun = 0x4029a0
распечатки.наконец, несмотря на
inline
предложение компилятору на самом деле расширить ОДН-vkladywfun()
, это игнорировать ваше предложение полностью, что понятно, потому чтоfun() = 111
в обеих строках.
-
Случай B:
Compile (обратите внимание на обратный порядок):
g++ -std=c++11 inline222.cpp inline111.cpp
выход:
inline111: fun() = 222, &fun = 0x402980 inline222: fun() = 222, &fun = 0x402980
Обсуждение:
этот случай утверждает то, что обсуждалось в Случае.
обратите внимание на важный момент, что если вы прокомментируете фактический вызов
fun()
на inline222.cpp (например комментарийcout
-заявлением inline222.cpp полностью) тогда, несмотря на порядок составления ваших переводческих единиц,fun()
будет создан экземпляр при первой встрече вызова в inline111.cpp, в результате чего в печать для Случае Б asinline111: fun() = 111, &fun = 0x402980
.
-
Дело C:
Compile (обратите внимание-O2):
g++ -std=c++11 -O2 inline222.cpp inline111.cpp
или
g++ -std=c++11 -O2 inline111.cpp inline222.cpp
выход:
inline111: fun() = 111, &fun = 0x402900 inline222: fun() = 222, &fun = 0x402900
Обсуждение:
- как описано здесь,
-O2
оптимизация поощряет компилятор к на самом деле расширить функции, которые могут быть встроены (обратите внимание также, что-fno-inline
и по умолчанию без параметров оптимизации). Как видно из outprint здесьfun()
на самом деле был встроенный расширенный (согласно его определению в том особенности единица перевода), в результате чего два разныеfun()
распечатки. Несмотря на это, есть еще единственный глобально связанный экземплярfun()
(как требуется стандартом), как видно из одинаковых&fun
распечатать.
- как описано здесь,
вам все равно нужно явно встроить свою функцию при выполнении специализации шаблона (если специализация включена .файл ч)
1) в настоящее время, практически никогда. Если это хорошая идея встроить функцию, компилятор сделает это без вашей помощи.
2) всегда. См. #1.
(отредактировано, чтобы отразить, что вы разбили свой вопрос на два вопроса...)
когда я не должен писать ключевое слово "inline" для функции/метода в C++?
Если функция определена в вы должны не написать ключевое слово.
когда компилятор не будет знать, когда сделать функцию / метод "inline"?
нет такой ситуации. Компилятор не может сделать функцию встроенной. Все, что он может сделать, это встроить некоторые или все вызовы функции. Это невозможно. поэтому, если у него нет кода функции (в этом случае компоновщик должен это сделать, если он может это сделать).
имеет ли значение, является ли приложение многопоточным, когда он пишет "inline" для функции/метода?
нет, это не важно.
на самом деле, почти никогда. Все, что вы делаете, это предлагаете компилятору сделать данную функцию встроенной (например, заменить все вызовы этой функции /ее тела). Конечно, нет никаких гарантий: компилятор может игнорировать директиву.
компилятор обычно делает хорошую работу по обнаружению + оптимизации таких вещей.
- когда компилятор не будет знать, когда сделать функцию / метод "inline"?
Это зависит от используемого компилятора. Не слепо верьте, что в настоящее время компиляторы знают лучше, чем люди, как встроить, и вы никогда не должны использовать его по соображениям производительности, потому что это директива связи, а не подсказка оптимизации. Хотя я согласен с тем, что идеологически эти аргументы правильны, столкновение с реальностью может быть другим.
после прочтения несколько потоков вокруг я попробовал из любопытства эффекты встроенного кода, который я просто работаю, и результаты заключались в том, что я получил измеримое ускорение для GCC и не ускорялся для компилятора Intel.
(более подробно: математическое моделирование с несколькими критическими функциями, определенными вне класса, GCC 4.6.3 (g++ -O3), ICC 13.1.0 (icpc-O3); добавление встроенных в критические точки, вызванное +6% ускорением с кодом GCC).
поэтому, если вы квалифицируете GCC 4.6 как современный компилятор, результатом является то, что встроенный директива по-прежнему имеет значение, если вы пишете задачи с интенсивным процессором и знаете, где именно находится узкое место.
gcc по умолчанию не вставляет никаких функций при компиляции без оптимизация включена. Я не знаю о visual studio-deft_code
Я проверил это для Visual Studio 9 (15.00.30729.01) путем компиляции с /FAcs и просмотра кода сборки: Компилятор производил вызовы функций-членов без оптимизации, включенной в debug режим. Даже если функция помечена как __forceinline, нет встроенного кода выполнения произведенный.
вы хотите поместить его в самом начале, перед типом возврата. Но большинство компиляторов игнорируют его. Если он определен и имеет меньший блок кода, большинство компиляторов все равно считают его встроенным.
при разработке и отладке кода, оставить inline
выход. Это усложняет отладку.
основная причина их добавления - помочь оптимизировать сгенерированный код. Как правило, это увеличивает пространство кода для скорости, но иногда inline
сохраняет пространство кода и время выполнения.
тратить такого рода мысли об оптимизации производительности до завершения алгоритма преждевременная оптимизация.
когда следует inline:
1.Когда вы хотите избежать накладных расходов, когда функция вызывается как передача параметров, передача управления, возврат управления и т. д.
2.Функция должна быть небольшой, часто вызываемой и делать встроенную действительно выгодна,так как согласно правилу 80-20, попробуйте сделать те функции встроенными, которые оказывают большое влияние на производительность программы.
Как мы знаем, что inline-это просто запрос к компилятору, похожему на register и это будет стоить вам при размере кода объекта.
Если вы не пишете библиотеку или не имеете особых причин, вы можете забыть о inline
и использовать link-оптимизация времени. Он удаляет требование о том, что определение функции должно быть в заголовке, чтобы оно рассматривалось для вставки между единицами компиляции, что именно то, что inline
позволяет.
(см. есть ли причина, почему не использовать оптимизацию времени ссылки?)