Подтвердить что ты не робот

Определение встроенного ключевого слова vs заголовка

Какая разница между использованием ключевого слова inline перед функцией и просто объявлением всей функции в заголовке?

так...

int whatever() { return 4; }

против

.h:

inline int whatever();

.cpp

inline int myClass::whatever()
{
    return 4;
}

что это делает:

inline int whatever() { return 4; }
4b9b3361

Ответ 1

Существует несколько аспектов:

Язык

  • Когда функция помечена ключевым словом inline, тогда ее определение должно быть доступно в TU или программа плохо сформирована.
  • Любая функция, определенная прямо в определении класса, неявно отмечена inline.
  • Функция, помеченная inline (неявно или явно), может быть определена в нескольких TU (в отношении ODR), тогда как это не относится к регулярным функциям.
  • Функции шаблона (не полностью специализированные) получают ту же обработку, что и inline.

Поведение компилятора

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

поведение компоновщика

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

Ответ 2

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

однако, для класса (как показано в вашем примере) большинство компиляторов неявно объявляют метод как inline (-fno-default-inline отключит это значение по умолчанию для GCC).

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

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

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

Ответ 3

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

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

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

Ответ 4

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

В принципе, он не имеет ничего общего с заголовком. Объявление всей функции в заголовке просто изменяет исходный файл, в котором находится источник функции. Ключевое слово Inline изменяет, где будет вставлена ​​результирующая скомпилированная функция - на своем собственном месте, чтобы каждый вызов шел туда или на месте каждого звонка (лучше для производительности). Однако компиляторы иногда выбирают, какие функции или методы делают inline для себя, а ключевые слова - просто предложения для компилятора. Даже функции, которые не были указаны в строке, могут быть выбраны компилятором, чтобы стать встроенным, если это дает лучшую производительность.

Ответ 5

Если вы связываете несколько объектов с исполняемым файлом, обычно должен быть только один объект, содержащий определение функции. Для int whatever() { return 4; } - любая единица перевода, которая используется для создания объекта, будет содержать определение (то есть исполняемый код) для функции whatever. Компилятор не будет знать, на какой из них можно направлять абонентов. Если предоставляется inline, тогда исполняемый код может быть или не быть встроенным на сайтах вызовов, но если ему не удастся, то компоновщику разрешено считать, что все определения одинаковы, и выберите один произвольно для прямого вызова. Если каким-то образом определения не совпадают, тогда он рассмотрел вашу ошибку и вы получите поведение undefined. Чтобы использовать inline, определение должно быть известно при компиляции вызова, поэтому ваша идея поместить встроенное объявление в заголовок и встроенное определение в .cpp файле будет работать только тогда, когда все вызывающие абоненты будут позже в том же .cpp файл - в общем случае он сломан, и вы ожидаете, что (в номинальном выражении) встроенное определение функции появится в заголовке, который объявит его (или для него будет одно определение без предварительного объявления).