Запись определения функции в заголовочные файлы на C++



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



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


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




  1. есть ли производительность или другие проблемы, если я ставлю эти определения функций в заголовочном файле? У меня будет много таких функций.

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

634   7  

7 ответов:

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

headera.h:

inline string method() {
    return something;
}

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

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

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

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

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

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

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

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

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

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

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

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

  2. да, компилятор действительно разворачивает файл заголовка, где он встречает операторы #include.

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

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

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

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

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

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

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

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

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

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

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

Comments

    Ничего не найдено.