Когда я должен написать ключевое слово 'inline' для функции/метода?
когда я должен написать ключевое слово inline для функции/метода в C++?
после того как увидел ответы на некоторые вопросы, некоторые связанные с этим вопросы:
когда я не напишите ключевое слово 'inline' для функции/метода в C++?
когда компилятор не будет знать, когда сделать функцию / метод'inline'?
имеет ли значение, если приложение многопоточный когда один пишет 'inline' для функции / метода?
12 ответов:
Ох, одна из моих любимых мозолей.
inlineбольше нравитсяstaticилиexternчем директива, указывающая компилятору встроить ваши функции.extern,static,inline- Это директивы компоновки, используемые почти исключительно компоновщиком, а не компилятором.говорят, что
inlineуказывает компилятору, что вы считаете, что функция должна быть встроена. Возможно, это было верно в 1998 году, но десять лет спустя компилятор не нуждается в таких намеках. Не упоминать люди обычно ошибаются, когда речь заходит об оптимизации кода, поэтому большинство компиляторов просто игнорируют "подсказку".
static- имя переменной/функции не может использоваться в других единицах перевода. Компоновщик должен убедиться, что он случайно не использует статически определенную переменную/функцию из другой единицы перевода.
extern- используйте это имя переменной / функции в этой единице перевода, но не делайте этого жалуйтесь, если это не определено. Компоновщик будет сортировать его и убедиться, что весь код, который пытался использовать какой-либо символ extern, имеет свой адрес.
inline- эта функция будет определена в нескольких единицах перевода, не беспокойтесь об этом. Компоновщик должен убедиться, что все единицы перевода используют один экземпляр переменной/функции.Примечание: как правило, объявление шаблонов
inlineis бессмысленно, так как они имеют семантику связиinlineуже. Однако,explicitспециализация и создание экземпляров шаблонов требуютсяinlineиспользовать.
конкретные ответы на ваши вопросы:
когда я должен написать ключевое слово 'inline' для функции/метода в C++?
только если вы хотите, чтобы функция была определена в заголовке. Точнее только тогда, когда функция определение может отображаться в нескольких единицах трансляции. Это хорошая идея, чтобы определить небольшие (как в одном лайнере) функции в заголовочном файле, поскольку это дает компилятору больше информации для работы при оптимизации кода. Это также увеличивает время компиляции.
когда я не должен писать ключевое слово 'inline' для функции/метода в C++?
не добавляйте inline только потому, что вы думаете, что ваш код будет работать быстрее, если компилятор inlines оно.
когда компилятор не будет знать, когда сделать функцию / метод'inline'?
как правило, компилятор сможет сделать это лучше, чем вы. Однако компилятор не имеет возможности встроить код, если у него нет определения функции. В максимально оптимизированном коде обычно все
privateметоды встроены, просите ли вы об этом или нет.как резерв для предупреждения встраивания в НКУ, использовать
__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; }
случае А:
Compile:
g++ -std=c++11 inline111.cpp inline222.cppвыход:
inline111: fun() = 111, &fun = 0x4029a0 inline222: fun() = 111, &fun = 0x4029a0Обсуждение:
даже ты должен иметь одинаковые определения вашего встроенного функции, компилятор C++ не флаг это, если это не так (на самом деле, из-за раздельной компиляции у него нет способа проверить это). Это ваша собственная обязанность, чтобы обеспечить это!
Линкер не жалуется Одно Правило Определения, а
fun()объявленinline. Однако, потому что inline111.cpp это первая единица перевода (которая на самом деле вызываетfun()) обработанный компилятором, компилятор создает экземплярfun()по его первый вызов-встреча в inline111.cpp. Если компилятор решит не расширенияfun()по его вызову из любого другого места в вашей программе (например с inline222.cpp), вызовfun()всегда будет связан с его экземпляром, произведенным из inline111.cpp (вызовfun()внутри inline222.cpp может также создать экземпляр в этой единице перевода, но он останется несвязанным). Действительно, это видно из тождественного&fun = 0x4029a0распечатки.наконец, несмотря на
inlineпредложение компилятору на самом деле расширить однострочныйfun(), это игнорировать ваше предложение полностью, что понятно, потому чтоfun() = 111в обеих строках.
Случай Б:
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()будет создан экземпляр при первом вызове encounter в inline111.cpp, что приводит к распечатке для Случае Б какinline111: fun() = 111, &fun = 0x402980.
Case 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и по умолчанию без параметров оптимизации). Как видно из отпечатка здесь,fun()на самом деле был inline expanded (согласно его определению в том особенности единица перевода), в результате чего два разныеfun()распечатки. Несмотря на это, есть еще единственный глобально связанный экземплярfun()(как требует стандарт), как видно из одинаковых&funраспечатать.
вам все равно нужно явно встроить свою функцию при выполнении специализации шаблона (если специализация включена .файл ч)
1) в настоящее время, в значительной степени никогда. Если это хорошая идея встроить функцию, компилятор сделает это без вашей помощи.
2) всегда. См. #1.
(отредактировано, чтобы отразить, что вы разбили свой вопрос на два вопроса...)
когда я не должен писать ключевое слово 'inline' для функции/метода в C++?
Если функция определена в вы должны не написать ключевое слово.
когда компилятор не будет знать, когда сделать функцию / метод'inline'?
нет такой ситуации. Компилятор не может сделать функцию встроенной. Все, что он может сделать, это встроить некоторые или все вызовы функции. Это не может сделать поэтому, если у него нет кода функции (в этом случае компоновщик должен сделать это, если он в состоянии это сделать).
имеет ли значение, если приложение многопоточно, когда пишется "inline" для функции/метода?
нет, это не важно.
на самом деле, почти никогда. Все, что вы делаете, это предлагаете компилятору сделать данную функцию встроенной (например, заменить все вызовы этой функции /w ее телом). Конечно, нет никаких гарантий: компилятор может игнорировать директиву.
компилятор обычно делает хорошую работу по обнаружению + оптимизации таких вещей.
- когда компилятор не будет знать, когда сделать функцию / метод'inline'?
Это зависит от используемого компилятора. Не слепо верьте, что в настоящее время компиляторы знают лучше, чем люди, как встроить, и вы никогда не должны использовать его по соображениям производительности, потому что это директива компоновки, а не подсказка оптимизации. Хотя я согласен с тем, что идеологически эти аргументы правильны, столкновение с реальностью может быть другим.
после прочтения несколько потоков вокруг я попробовал из любопытства эффекты inline на коде, который я просто работаю, и результаты были в том, что я получил измеримое ускорение для GCC и не ускорялся для компилятора Intel.
(более подробно: математическое моделирование с несколькими критическими функциями, определенными вне класса, GCC 4.6.3 (g++ -O3), ICC 13.1.0 (icpc-O3); добавление встроенных критических точек вызвало ускорение +6% с кодом GCC).
поэтому, если вы квалифицируете GCC 4.6 как современный компилятор, результатом является то, что inline директива по-прежнему имеет значение, если вы пишете задачи с интенсивным ЦП и знаете, где именно находится узкое место.
gcc по умолчанию не вставляет никаких функций при компиляции без оптимизация включена. Я не знаю о visual studio-deft_code
Я проверил это для Visual Studio 9 (15.00.30729.01) путем компиляции с /FAcs и просмотра кода сборки: Компилятор производил вызовы функций-членов без оптимизации, включенной в debug режим. Даже если функция помечена __forceinline, нет встроенного кода среды выполнения произведенный.
вы хотите поставить его в самом начале, перед возвращаемым типом. Но большинство компиляторов игнорируют его. Если он определен и имеет меньший блок кода, большинство компиляторов считают его встроенным в любом случае.
при разработке и отладке кода, оставить
inlineвыход. Это усложняет отладку.основная причина их добавления заключается в том, чтобы помочь оптимизировать сгенерированный код. Обычно это торгует увеличенным кодовым пространством для скорости, но иногда
inlineсохраняет как пространство кода, так и время выполнения.использование такого рода мысли об оптимизации производительности до завершения алгоритма является преждевременная оптимизация.
когда нужно встроить:
1.Когда вы хотите избежать накладных расходов, когда функция вызывается как передача параметров, передача управления, возврат управления и т. д.
2.Функция должна быть небольшой, часто вызываемой и делать inline действительно выгодно,так как в соответствии с правилом 80-20, попробуйте сделать те функции inline, которые оказывают значительное влияние на производительность программы.
Как мы знаем, что inline-это просто запрос к компилятору, похожий на register и это будет стоить вам при размере кода объекта.
Если вы не пишете библиотеку или не имеете особых причин, вы можете забыть о
inlineи использовать связь-оптимизация времени. Он устраняет требование о том, что определение функции должно быть в заголовке, чтобы оно рассматривалось для вставки между единицами компиляции, что именноinlineпозволяет.(см. есть ли причина, почему не использовать оптимизацию времени ссылки?)
Comments