Всегда ли определение функции внутри заголовка заставляет компилятор обрабатывать ее как встроенную? - PullRequest
6 голосов
/ 07 декабря 2009

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

Ответы [ 4 ]

16 голосов
/ 07 декабря 2009

"определение функции c ++ внутри заголовочного файла класса делает функцию встроенной"

Это не правда. Определение функции (то есть предоставление тела функции вместо простого объявления) внутри определения класса делает его встроенным. Под словом «делает его встроенным» я подразумеваю то же самое, что и для него встроенное ключевое слово. Но определения классов не обязательно должны быть в заголовках, а заголовки могут содержать иные вещи, чем определения классов.

Таким образом, в этом примере функция foo неявно встроена. Функция bar не является встроенной:

struct Foo {
    void foo() {}
    void bar();
};

void Foo::bar() {}

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

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

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

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

Независимо от того, определена ли функция в заголовке или в файле cpp, она сама по себе абсолютно не влияет Вы можете смело представить, что #include выполняет копирование и вставку заголовочного файла в файл cpp в препроцессоре до того, как компилятор его увидит. Если функция определена в той же единице перевода, что и ее вызов, то код функции доступен для вставки компилятором. Если они находятся в разных единицах перевода, то код недоступен, и вызов может быть встроен только компоновщиком с оптимизацией всей программы или подобным. «Единица перевода» более или менее означает «файл cpp после того, как все заголовки были скопированы и вставлены в него».

3 голосов
/ 07 декабря 2009

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

1 голос
/ 07 декабря 2009

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

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

0 голосов
/ 07 декабря 2009

Если вы поместите определение бесплатной не шаблонной функции в файл заголовка, вы получите определение функции в каждом файле .cpp, который включает заголовок (прямо или косвенно). Это может привести к проблемам при линковке.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...