Когда я должен написать ключевое слово 'inline' для функции/метода?



когда я должен написать ключевое слово inline для функции/метода в C++?



после того как увидел ответы на некоторые вопросы, некоторые связанные с этим вопросы:




  • когда я не напишите ключевое слово 'inline' для функции/метода в C++?


  • когда компилятор не будет знать, когда сделать функцию / метод'inline'?


  • имеет ли значение, если приложение многопоточный когда один пишет 'inline' для функции / метода?


595   12  

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 методы встроены, просите ли вы об этом или нет.

    как резерв для предупреждения встраивания в НКУ, использовать __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
    

    Обсуждение:

    1. даже ты должен иметь одинаковые определения вашего встроенного функции, компилятор C++ не флаг это, если это не так (на самом деле, из-за раздельной компиляции у него нет способа проверить это). Это ваша собственная обязанность, чтобы обеспечить это!

    2. Линкер не жалуется Одно Правило Определения, а fun() объявлен inline. Однако, потому что inline111.cpp это первая единица перевода (которая на самом деле вызывает fun()) обработанный компилятором, компилятор создает экземпляр fun() по его первый вызов-встреча в inline111.cpp. Если компилятор решит не расширения fun() по его вызову из любого другого места в вашей программе (например с inline222.cpp), вызов fun() всегда будет связан с его экземпляром, произведенным из inline111.cpp (вызов fun() внутри inline222.cpp может также создать экземпляр в этой единице перевода, но он останется несвязанным). Действительно, это видно из тождественного &fun = 0x4029a0 распечатки.

    3. наконец, несмотря на inline предложение компилятору на самом деле расширить однострочный fun(), это игнорировать ваше предложение полностью, что понятно, потому что fun() = 111 в обеих строках.


  • Случай Б:

    Compile(обратите внимание на обратный порядок):

    g++ -std=c++11 inline222.cpp inline111.cpp
    

    выход:

    inline111: fun() = 222, &fun = 0x402980
    inline222: fun() = 222, &fun = 0x402980
    

    Обсуждение:

    1. этот случай утверждает то, что обсуждалось в Случае.

    2. обратите внимание на важный момент, что если вы прокомментируете фактический вызов 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
    

    Обсуждение:

    1. как описано здесь,-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

    Ничего не найдено.