#c #function #header
#c #функция #заголовок
Вопрос:
В последнее время я начал помещать все больше и больше функций в заголовочные файлы, в основном для удобства. Но я боюсь, что, возможно, я переусердствовал, мои заголовки полны включений, и я не уверен, что это хорошая идея.
Каковы ваши эмпирические правила для перемещения функций из или в файлы заголовков?
На случай, если вам интересно, я говорю о разработке приложений, а не библиотек.
Редактировать:
Я думаю, будет полезно, если я обрисую плюсы / минусы встроенных (естественно) функций заголовка по сравнению с функциями реализации с моей точки зрения:
Pro встроенный:
- Более чистый / лаконичный.
- Нет необходимости в дублировании подписи.
- Нет необходимости изменять какой-либо Makefile для ссылки на новые файлы.
- Мгновенная возможность вводить параметры шаблона.
Contra inline:
- Увеличенное время компиляции (меня это мало волнует)
- Многие включения в заголовках (не должны быть такой большой проблемой, если они используют guards)
В соответствии с этим, кажется хорошей идеей размещать практически все функции в заголовках, и я считаю, что это довольно близко к тому, что делают STL и Boost (хотя это библиотеки, в отличие от моего кода).
Ответ №1:
Одно из моих самых нерушимых правил: в заголовочных файлах разрешены только встроенные тела функций. Все остальное вызывает проблемы с несколькими определениями на этапе компоновки.
Заголовки следует оставлять преимущественно для объявлений, а не для определений. У меня есть исключения из этого правила (являющегося гибким типом), но ни одно из них не включает в себя тела не встроенных функций.
Ответ №2:
Мое эмпирическое правило гласит: «Не в заголовке, если только это не обязательно». А что касается удобства, считаете ли вы увеличение времени компиляции удобным?
Комментарии:
1. Дополнение / уточнение: время компиляции может увеличиться не только из-за тел функций, но и из-за включений, которые требуются для реализации функции.
2. Я могу только согласиться. Чем меньше этого в заголовках, тем лучше.
Ответ №3:
Есть несколько очевидных технических аспектов — шаблоны и встроенные функции должны быть в заголовках — заголовки, включенные из нескольких единиц перевода, должны опасаться правила единого определения — более прямолинейно, вам понадобилась бы чертовски веская причина, чтобы даже рассмотреть возможность размещения нестандартной реализации функции в заголовке, и я не могу вспомнить ни одного случая, когда у меня даже возникало искушение.
Итак, вопрос сводится к:
встроенный в заголовок или внешний в файле реализации?
Факторы:
- вы говорите, что разрабатываете код прикладного уровня, а не библиотеки, поэтому вам (в настоящее время) не нужно беспокоиться о том, что другие команды будут зависеть от вашего кода, и не сводить к минимуму их необходимость перекомпиляции (вместо простой перелинковки), не допуская нарушения реализации
- НО если вы пишете хороший код, который потенциально может стать полезным для других команд, то вы можете пожалеть, что не сохранили реализацию в тайне
- встроенные по сравнению с внешними обычно представляют собой накладные расходы примерно на порядок для тривиальных функций получения / установки данных… если у вас есть функции, которые неоднократно вызываются из критически важного для производительности кода, то у вас есть основания предпочесть встраивание
- реализация в заголовке (особенно если она смешана с объявлениями) часто может запутать API, но иногда на самом деле делает код более самодокументируемым
- локализация и устраненная избыточность (объединение объявлений / определений) определенно устраняют вероятность опечаток / ошибок и часто могут повысить производительность
Итог: если вы обнаруживаете, что делаете это все чаще и чаще, то это, очевидно, работает на вас, и нет особых причин думать, что вы вот-вот прогорите. Следите за потенциальными проблемами, но не перегружайте материал, основываясь на какой-то гипотетической проблеме, которая вряд ли материализуется.
Ответ №4:
Хороший стандарт кодирования подскажет вам реализовать методы и функции в исходном файле (cpp).
Если вы предпочитаете это, вы можете реализовать шаблоны и встроенные функции в заголовке.
Ответ №5:
Поскольку это было помечено как C
, почему бы вам не разделить их на логические class
элементы?
Обычно у меня есть одно class
объявление в заголовочном файле и его определение в соответствующем исходном файле.
Комментарии:
1. Ну, C — это не Java: не все должно быть обернуто в классы. Иногда свободная функция просто имеет смысл.
2. И даже для классов — это болезненно манипулировать десятками файлов, каждый из которых содержит полдюжины линейных классов, поэтому я бы не сказал, что это руководство широко применимо. (Я больше склоняюсь к другой крайности — я рад помещать небольшие приложения в один файл, если только нет явно используемых подсистем, и у меня это хорошо работает, хотя, по общему признанию, любая потребность / инструментарий для тестовых случаев может изменить баланс.)
Ответ №6:
Я использую два правила
1) Если это встроенные функции
2) Если это шаблонная функция.
Комментарии:
1. С добавленными правилами: только
inline
если профилировщик говорит, что вы должны, и используйте шаблоны только в том случае, если вам нужно создавать их экземпляры несколько раз.
Ответ №7:
Во-первых, шаблонная функция должна быть помещена в заголовки.
Кроме того, в заголовки могут быть помещены функции с пустым телом, такие как конструктор по умолчанию или виртуальный деструктор по умолчанию.
Я никогда не использую inline
, потому что компилятор этого не гарантирует.