Функции, определенные в заголовках, гарантированные навязчивыми?

StackOverflow https://stackoverflow.com/questions/2391294

  •  25-09-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

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

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

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

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

Другие советы

Из C ++ FAQ Lite:

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

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

если ты определять Функция с внешним соединением в заголовочном файле и включает его в более чем один блок перевода, вы получите ошибку компиляции (точнее: Linker EroRR) для нарушения правила одного определения (ODR). Таким образом, ответ «нет»: определение функции в заголовом файле не будет принята компилятором в виде подсказки в Inlining и не оправдываем вас от соблюдения требований ODR. Не только такие функции не гарантированы, но, скорее всего, ваша программа даже не скомпилируется.

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

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

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

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

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

Эффект этого заключается в

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top