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

Определение функции записи в файлах заголовков в С++

У меня есть класс, который имеет много небольших функций. Маленькими функциями я называю функции, которые не выполняют никакой обработки, а просто возвращают буквальное значение. Что-то вроде:

string Foo::method() const{
    return "A";
}

Я создал файл заголовка "Foo.h" и исходный файл "Foo.cpp". Но поскольку функция очень мала, я думаю о ее размещении в самом файле заголовка. У меня есть следующие вопросы:

  • Есть ли какая-либо производительность или другие проблемы, если я поместил это определение функции в файл заголовка? У меня будет много таких функций.
  • Насколько я понимаю, когда компиляция выполнена, компилятор расширит файл заголовка и поместит его туда, где он включен. Это правильно?
4b9b3361

Ответ 1

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

headera.h:

inline string method() {
    return something;
}

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

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

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

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

Ответ 2

В зависимости от вашего компилятора и его настроек он может выполнять любое из следующих действий:

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

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

Другая вещь, о которой нужно помнить, заключается в том, что если вы экспортируете класс в библиотеку DLL/shared (неважная идея IMHO, но люди все равно это делают), вам нужно быть очень осторожным с встроенными функциями. Если компилятор, который построил DLL, решает, что функция должна быть встроена, у вас есть несколько потенциальных проблем:

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

Ответ 3

Будет возрастать производительность, поскольку реализация в файлах заголовков неявно встроена. Поскольку вы упомянули, что ваши функции малы, встроенная операция будет настолько полезной для вас IMHO.

То, что вы говорите о компиляторе, также истинно. Нет никакой разницы для компилятора — кроме того, что встраивание — между кодом в файле заголовка или .cpp.

Ответ 4

  • Если ваши функции настолько просты, сделайте их встроенными, и вам все равно придется вставлять их в файл заголовка. Помимо этого, любые соглашения - это только те соглашения.

  • Да, компилятор расширяет заголовочный файл, где он встречает инструкции #include.

Ответ 5

Это зависит от стандартов кодирования, которые применяются в вашем случае, но:

Маленькие функции без циклов и все остальное должны быть встроены для повышения производительности (но немного более крупный код - важно для некоторых ограниченных или встроенных приложений).

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

Перед созданием компилятором объектного файла вызывается препроцессор (опция -g для gcc), и результат отправляется компилятору, который создает объект из кода.

Итак, более короткий ответ:

- Объявление функций в заголовке полезно для скорости (но не для пробела) -

Ответ 6

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

Ответ 7

С++ не будет жаловаться, если вы это сделаете, но, вообще говоря, вы не должны.

когда вы # включаете файл, все содержимое включенного файла вставляется в момент включения. Это означает, что любые определения, которые вы помещаете в свой заголовок, копируются в каждый файл, содержащий этот заголовок.

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

Иногда исключаются тривиальные функции, которые вряд ли будут меняться (например, если определение функции - одна строка).