Эмпирические правила для размещения функций в файлах заголовков

#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 , потому что компилятор этого не гарантирует.