Может ли ключевое слово inline изменять поведение функции. [Дубликат]

Функция:

public float simpleSimilarity(String u, String v) {
    String[] a = u.split(" ");
    String[] b = v.split(" ");

    long correct = 0;
    int minLen = Math.min(a.length, b.length);

    for (int i = 0; i < minLen; i++) {
        String aa = a[i];
        String bb = b[i];
        int minWordLength = Math.min(aa.length(), bb.length());

        for (int j = 0; j < minWordLength; j++) {
            if (aa.charAt(j) == bb.charAt(j)) {
                correct++;
            }
        }
    }

    return (float) (((double) correct) / Math.max(u.length(), v.length()));
}

Тест:

String a = "This is the first string.";

String b = "this is not 1st string!";

// for exact string comparison, use .equals

boolean exact = a.equals(b);

// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote

float similarity = simple_similarity(a,b);
425
задан IAmInPLS 2 December 2017 в 11:18
поделиться

12 ответов

О, человек, один из моих питомцев.

inline больше похож на static или extern, чем на директиву, сообщающую компилятору встроить ваши функции. extern, static, inline являются директивами привязки, которые используются почти исключительно компоновщиком, а не компилятором.

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

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

Примечание. Как правило, объявление шаблонов inline бессмысленно, так как они имеют семантику связи inline уже. Тем не менее, специализация explicit и создание экземпляров шаблонов требуют использования inline .


Конкретные ответы на ваши вопросы:

  • Когда следует писать ключевое слово 'inline' для функции / метода в C ++? Только когда вы хотите, чтобы функция была определена в заголовке. Точнее, только когда определение функции может отображаться в нескольких единицах перевода. Это хорошая идея, чтобы определить небольшие (как в одном лайнере) функции в файле заголовка, поскольку он дает компилятору больше информации для работы с оптимизацией кода. Это также увеличивает время компиляции.
  • Когда я не должен писать ключевое слово 'inline' для функции / метода в C ++? Не добавляйте встроенную строку только потому, что считаете, что ваш код будет работать быстрее, если компилятор сделает это.
  • Когда компилятор не знает, когда нужно сделать функцию / метод «inline»? Как правило, компилятор сможет сделать это лучше вас. Однако компилятор не имеет возможности встроить код, если он не имеет определения функции. Обычно в максимально оптимизированном коде все методы private встроены независимо от того, запрашиваете вы это или нет. Для предотвращения встраивания в GCC используйте __attribute__(( noinline )), а в Visual Studio используйте __declspec(noinline).
  • Имеет ли значение, если приложение многопоточно, когда вы записываете «inline» для функции / метода ? Многопоточность никак не влияет на inlining.
683
ответ дан dekuShrub 15 August 2018 в 15:21
поделиться
  • 1
    +1 Лучшее описание inline, которое я видел в ... (навсегда). Теперь я разорву вас и использую это во всех моих объяснениях ключевого слова inline. – Martin York 19 November 2009 в 02:37
  • 2
    @Ziggy, то, что я пытался сказать, было то, что компилятор встраивания и ключевое слово inline не связаны. Однако у вас есть правильная идея. Как правило, угадать, что было бы улучшено путем inline, очень подвержено ошибкам. Исключение из этого правила - это один лайнер. – deft_code 15 August 2011 в 19:50
  • 3
    Этот ответ немного смущает меня. Вы говорите все это о том, что компилятор способен встраивать / не встроить вещи лучше. Затем вы говорите, что вы должны поместить в заголовок один лайнер / мелкие функции и что компилятор не может встроить код без определения функции. Разве это не противоречиво? Почему бы просто не поместить все в файл cpp и не разрешить компилятору? – user673679 3 April 2013 в 18:22
  • 4
    Компилятор будет только встроенными вызовами функций, где определение доступно на сайте вызова. Если оставить все функции в файле cpp, это ограничит вложение в этот файл. Я предлагаю определить малые однострочные линии inline в .h, поскольку затраты на скорость компиляции незначительны, и вы почти гарантированно, что компилятор включит вызов. Моя точка зрения о разработке компилятора заключается в том, что это порт черного искусства оптимизации, при котором ваш компилятор намного лучше, чем вы. – deft_code 3 April 2013 в 19:21
  • 5
    Всякий раз, когда я читаю что-то на счет совокупного знания Интернета , я должен думать о знаменитой цитате Джона Лоутона: . Ирония информационной эпохи заключается в том, что она придала новую респектабельность неосведомленному мнению. – IInspectable 11 September 2013 в 18:58

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

2) Всегда. См. № 1.

(Отредактировано с учетом того, что вы нарушили свой вопрос на два вопроса ...)

17
ответ дан Aric TenEyck 15 August 2018 в 15:21
поделиться
  • 1
    Да. Встроенная строка является лишь подсказкой для компилятора, и вы можете игнорировать вас. В наши дни компилятор, вероятно, знает лучше, чем программист, функции которого лучше всего встроены. – Mark Byers 18 November 2009 в 22:51
  • 2
    Да, но это менее актуально - для того, чтобы функция была встроена, ее тело должно находиться в одном модуле компиляции (например, в заголовке). Это менее распространено в программах на C. – Michael Kohne 18 November 2009 в 22:57
  • 3
    определение шаблона функции, не являющегося членом (например, нестатического шаблона функции), не требует встроенного. См. Одно правило определения (3.2 / 5). – deft_code 19 November 2009 в 00:42
  • 4
    -1: inline по-прежнему необходимо, например, чтобы определить функцию в файле заголовка (и это необходимо для встраивания такой функции в несколько единиц компиляции). – Melebius 18 November 2014 в 12:25
  • 5
    @ Étienne, специфичный для реализации. В стандарте есть одно правило определения, а это означает, что если вы наивно включаете определение функции в несколько единиц перевода, вы получите сообщение об ошибке. Но если эта функция имеет спецификатор inline, его экземпляры автоматически сжимаются в один компоновщиком, а ODR не используется. – Ruslan 22 November 2016 в 15:11

Когда нужно встроить:

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

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

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

-1
ответ дан Benjamin 15 August 2018 в 15:21
поделиться
  • 1
    «inline» - это просто запрос к компилятору, подобный регистру ». Они похожи, потому что ни запросы, ни какие-либо связанные с оптимизацией. inline потерял свой статус подсказки оптимизации, и большинство компиляторов используют его только для того, чтобы сделать допущения для нескольких определений - как ИМО, которым они должны. Более того, поскольку C ++ 11, register полностью устарел из-за своего прежнего значения «Я знаю лучше, чем компилятор, как оптимизировать»: теперь это просто зарезервированное слово без текущего значения. – underscore_d 4 October 2016 в 20:20
  • 2
    @underscore_d: Gcc до сих пор слушает inline до некоторой степени. – MikeMB 5 December 2016 в 09:27

Вам все равно нужно явно встраивать свою функцию при выполнении специализированной специализации (если специализация находится в файле .h)

26
ответ дан BostonLogan 15 August 2018 в 15:21
поделиться

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

(Но см. Есть ли какая-либо причина почему бы не использовать оптимизацию времени ссылки? )

-1
ответ дан Community 15 August 2018 в 15:21
поделиться

В действительности, почти никогда. Все, что вы делаете, означает, что компилятор делает заданную функцию встроенной (например, заменяет все вызовы на эту функцию / w ее тело). Конечно, нет никаких гарантий: компилятор может игнорировать директиву.

Компилятор обычно хорошо справляется с обнаружением + оптимизации таких вещей.

4
ответ дан DarkSquid 15 August 2018 в 15:21
поделиться
  • 1
    Проблема в том, что inline имеет разницу семантической в C ++ (например, в способе обработки нескольких определений), что важно в некоторых случаях (например, шаблоны). – Pavel Minaev 18 November 2009 в 23:55
  • 2
    inline используется для разрешения случаев, когда символ имеет несколько определений. Однако шаблоны уже обрабатываются языком. Одним из исключений является специализированная функция шаблона, которая больше не имеет параметров шаблона (template & lt; gt;). Они рассматриваются как функции, отличные от шаблонов, поэтому для ссылки требуется ключевое слово inline. – deft_code 19 November 2009 в 00:47

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

Для двух исходных файлов, таких как:

  • 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: Скомпилировать :
    g++ -std=c++11 inline111.cpp inline222.cpp
    
    Выход :
    inline111: fun() = 111, &fun = 0x4029a0
    inline222: fun() = 111, &fun = 0x4029a0
    
    Обсуждение : Даже у вас должно быть одинаковое определение ваших встроенных функций, компилятор C ++ не указывает его, если это не (на самом деле, из-за отдельной компиляции у него нет способов проверить это). Это ваша обязанность обеспечить это! Linker не жалуется на Одно правило определения , поскольку fun() объявлено как inline. Однако, поскольку inline111.cpp является первой единицей перевода (которая на самом деле вызывает fun()), обработанной компилятором, компилятор создает экземпляр fun() на его первом вызове-вызове inline111.cpp. Если компилятор решает не расширять fun() по его вызову из любого места в вашей программе (, например из inline222.cpp), вызов fun() всегда будет связан с его экземпляром, созданным из inline111. cpp (вызов fun() внутри inline222.cpp также может привести экземпляр в этой единицы перевода, но он останется несвязанным). Действительно, это видно из идентичных распечаток &fun = 0x4029a0. Наконец, несмотря на предложение inline компилятору на самом деле расширить однострочный fun(), он полностью игнорирует ваше предложение, что ясно, потому что fun() = 111 в обе линии.

  • Случай B: Скомпилировать (уведомление об обратном порядке) :
    g++ -std=c++11 inline222.cpp inline111.cpp
    
    Выход :
    inline111: fun() = 222, &fun = 0x402980
    inline222: fun() = 222, &fun = 0x402980
    
    Обсуждение : этот случай утверждает то, что обсуждалось в случае А. Обратите внимание на важный момент, что если вы закомментируете фактический вызов fun() inline222.cpp ( ] например, полностью закомментировать cout -statement inline222.cpp), то, несмотря на порядок компиляции ваших единиц перевода, fun() будет создан при первом вызове вызова inline111.cpp, для случая B как inline111: fun() = 111, &fun = 0x402980.

  • Случай C: Компиляция (уведомление -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() фактически был встроенным расширенным (согласно его определению в этой особой блоке трансляции), в результате чего два разных fun() распечатки. Несмотря на это, все еще существует только один глобально связанный экземпляр fun() (как требуется стандартом), как видно из идентичного &fun распечатки.
25
ответ дан Jacob 15 August 2018 в 15:21
поделиться
  • 1
    Ваш ответ - иллюстративная статья о том, почему язык делает такие функции inline неопределенным. – R Sahu 29 May 2018 в 15:50

gcc по умолчанию не строит никаких функций при компиляции без оптимизации. Я не знаю о visual studio - deft_code

Я проверил это для Visual Studio 9 (15.00.30729.01), компилировав / FAcs и посмотрев на код сборки: компилятор произвел вызовы функции-члены без оптимизации включены в режиме отладки. Даже если функция отмечена __forceinline, не создается встроенный код времени выполнения.

2
ответ дан Jedzia 15 August 2018 в 15:21
поделиться
  • 1
    Включить / Стена, чтобы рассказать о том, какие функции отмечены как встроенные, но на самом деле не вставлены – paulm 2 January 2014 в 17:17

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

0
ответ дан Jeremy Morgan 15 August 2018 в 15:21
поделиться

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

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

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

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

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

Нет, это вообще не имеет значения.

8
ответ дан Johannes Schaub - litb 15 August 2018 в 15:21
поделиться
  • Когда компилятор не знает, когда делать функцию / метод «inline»?

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

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

(Подробнее: математическое моделирование с несколькими критическими функциями, определенными вне класса, GCC 4.6.3 (g ++ -O3), ICC 13.1.0 (icpc-O3), добавив inline к критическим точкам, вызвав + 6% ускорение с кодом GCC).

Итак, если вы квалифицируете GCC 4.6 как современный компилятор, результатом является то, что директива inline по-прежнему имеет значение, если вы пишете CPU интенсивные задачи и знать, где именно находится узкое место.

4
ответ дан meda beda 15 August 2018 в 15:21
поделиться
  • 1
    Я бы хотел увидеть больше доказательств, подтверждающих ваши претензии. Просьба представить код, который вы тестируете, а также вывод ассемблера с ключевым словом и без него. Любое количество вещей могло бы дать вам преимущества в производительности. – void.pointer 13 May 2014 в 21:59
  • 2
    Наконец, кто-то, кто не только повторяет то, что говорят другие, но действительно проверяет эти утверждения. Gcc действительно все еще считает ключевое слово inline в качестве подсказки (я думаю, что clang полностью игнорирует его). – MikeMB 5 December 2016 в 09:21
  • 3
    @ void.pointer: Почему так трудно поверить? Если оптимизаторы были уже совершенны, то новые версии не смогли улучшить производительность программы. Но они регулярно делают. – MikeMB 5 December 2016 в 09:23

При разработке и отладке кода оставьте inline. Это усложняет отладку.

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

Рассекая эту мысль о оптимизации производительности до завершения алгоритма преждевременная оптимизация .

-1
ответ дан wallyk 15 August 2018 в 15:21
поделиться
  • 1
    inline функции, как правило, не встроены, если они не компилируются с оптимизацией, поэтому они никак не влияют на отладку. Помните, что это намек, а не требование. – Pavel Minaev 18 November 2009 в 23:54
  • 2
    gcc по умолчанию не выполняет никаких функций при компиляции без оптимизации. Я не знаю о визуальной студии – deft_code 19 November 2009 в 00:07
  • 3
    Я работал над огромным проектом g ++, в котором была включена отладка. Возможно, другие варианты не позволили, но функции inline были встроены. В них невозможно было установить в них осмысленную точку останова. – wallyk 19 November 2009 в 00:19
  • 4
    включение отладки не прекращает встраивание в gcc. Если какая-либо оптимизация, где включена (-O1 или выше), то gcc попытается установить наиболее очевидные случаи. Традиционно GDB испытывает трудности с точками останова и конструкторами, особенно встроенными конструкторами. Но это исправлено в последних версиях (по крайней мере, 6,7, возможно, раньше). – deft_code 19 November 2009 в 00:51
  • 5
    Добавление inline ничего не сделает для улучшения кода в современном компиляторе, который может выяснить, является ли встроенным или нет самостоятельно. – David Thornley 20 November 2009 в 23:22
Другие вопросы по тегам:

Похожие вопросы: