2012-04-11 2 views
25

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

так ...

int whatever() { return 4; } 

против

.h:

inline int whatever(); 

.cpp:

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

по этому вопросу, что делает это сделать:

inline int whatever() { return 4; } 

ответ

10

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

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

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

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

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

2

Этот вопрос многое объясняет о встроенных функциях What does __inline__ mean ? (даже если речь шла о рядный ключевое слово.)

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

1

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

28

Есть несколько аспектов:

Язык

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

Compiler поведение

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

поведение Linker

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

Что вы подразумеваете под «TU» и «ODR»? – WiSaGaN

+4

@WiSaGaN: TU = единица перевода: грубо, предварительно обработанный исходный файл. ODR = одно правило определения: требуется, чтобы все определения функции/класса были идентичны на уровне символов через TU. –

+0

На уровне персонажа или уровне маркера? – fredoverflow

9

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

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

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

Смежные вопросы