Гарантируются ли функции, определенные в заголовках, как встроенные? - PullRequest
6 голосов
/ 06 марта 2010

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

Ответы [ 5 ]

11 голосов
/ 06 марта 2010

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

Поэтому, когда вы определяете функцию в файле заголовка и включаете этот файл заголовка в файл, вы просто вводите функцию прямо в файл.Итак, теперь возникает вопрос: «Компилятор выбирает встроенные объекты, основанные на эвристике?»

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

Однако мы подошли к интересному моменту.Представьте, что у вас есть функция в заголовке, и вы включаете этот заголовок в несколько исходных файлов.Затем у вас будет несколько определений функции в разных единицах перевода, и это нарушает правило одного определения.Ergo, вы получите ошибки компиляции.(Ошибка компоновщика обычно выглядит примерно так: «Ошибка, функция x уже определена в y»). Вы можете использовать ключевое слово inline и больше не нарушать ODR.

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

4 голосов
/ 06 марта 2010

Из C ++ FAQ Lite :

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

2 голосов
/ 06 марта 2010

Если вы определите функцию с внешней связью в заголовочном файле и включите ее в более чем одну единицу перевода, вы получите ошибку компиляции (точнее: linker erorr) за нарушение одного правила определения (УСО). Поэтому ответ «нет»: определение функции в заголовочном файле не будет восприниматься компилятором как подсказка для вставки и не освобождает вас от соблюдения требований ODR. Не только такие функции гарантированно не встроены, но, скорее всего, ваша программа даже не скомпилируется.

Для того, чтобы определить функцию в заголовочном файле и избавиться от нее, вы должны либо дать ей внутреннюю связь (объявить ее static, и в итоге получить отдельную функцию в каждой единице перевода), либо явно объявить ее inline.

Что касается эвристики ... Современные компиляторы обычно рассматривают практически любую функцию для встраивания (применяя эвристику), независимо от того, где она определена и объявлена ​​ли она явно inline или нет.

2 голосов
/ 06 марта 2010

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

1 голос
/ 06 марта 2010

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

Есть также два разных значения слова «inline», которые нужно знать:

Функция может быть встроенной , как определено стандартом C ++: это делается либо с помощью префикса функции перед ключевым словом inline, либо, если это функция-член, путем определения ее на месте внутри определения класса.

Эффект от этого до

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

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

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

...