Александреску Андрей
Шрифт:
Когда мы начинаем использовать С++, то все достаточно быстро уясняем, что заголовочный файл наподобие
будучи включен больше чем в один исходный файл, ведет при компиляции к ошибкам дублирования символов во время компоновки. Причина проста: каждый исходный файл в действительности определяет и выделяет пространство для
Реальные же объявления располагаются в одном файле реализации:
He определяйте в заголовочном файле и статические объекты уровня пространства имен, например:
Такое некорректное использование ключевого слова
Не пытайтесь обойти эту ситуацию при помощи использования безымянных пространств имен в заголовочных файлах, поскольку результат будет ничуть не лучше:
В заголовочных файлах могут находиться следующие объекты с внешним связыванием.
• Встраиваемые функции. Они имеют внешнее связывание, но компоновщик гарантированно не отвергает многократные копии. Во всем остальном они ведут себя так же, как и обычные функции. В частности, адрес встраиваемой функции гарантированно будет единственным в пределах программы.
• Шаблоны функций. Аналогично встраиваемым функциям, инстанцирования ведут себя так же, как и обычные функции, с тем отличием, что их дубликаты приемлемы (и должны быть идентичны). Само собой разумеется, хороший компилятор устранит излишние копии.
• Статические данные-члены шаблонов классов. Они могут оказаться особенно сложными для компоновщика, но это уже не ваша проблема — вы просто определяете их в своем заголовочном файле и предоставляете сделать все остальное компилятору и компоновщику.
Кроме того, методика инициализации глобальных данных, известная как "Счетчики Шварца" ("Schwarz counters"), предписывает использование в заголовочном файле статических данных (или безымянных пространств имен). Джерри Шварц (Jerry Schwarz) использовал эту методику для инициализации стандартных потоков ввода-вывода
[Dewhurst03] §55 • [Ellis90] §3.3 • [Stroustrup00] §9.2, §9.4.1
62. Не позволяйте исключениям пересекать границы модулей
Не бросайте камни в соседский огород — поскольку нет повсеместно распространенного бинарного стандарта для обработки исключений С++, не позволяйте исключениям пересекать распространяться между двумя частями кода, если только вы не в состоянии контролировать, каким компилятором и с какими опциями скомпилированы обе эти части кода. В противном случае может оказаться, что модули не поддерживают совместимые реализации распространения исключений. Обычно это правило сводится к следующему: не позволяйте исключениям пересекать границы модулей/подсистем.
Стандарт С++ не определяет способ реализации распространения исключений, и не имеется никакого стандарта де-факто, признанного большинством систем. Механика распространения исключений варьируется не только в зависимости от операционной системы и компилятора, но и в зависимости от опций компиляции, использованных для компиляции данного модуля данным компилятором в данной операционной системе. Следовательно, приложение должно предотвращать несовместимость обработки исключений путем экранирования границ каждого из своих основных модулей, под которыми подразумеваются части приложения, для которых разработчик может гарантировать, что для их компиляции использован один и тот же компилятор и одни и те же опции компиляции.