Стандарты программирования на С++. 101 правило и рекомендация | страница 107
>static int fudgeFactor;
>static string hello("Hello, world!");
>static void foo() { /* ... */ }
Такое некорректное использование ключевого слова >static
более опасно, чем простое определение глобальных объектов в заголовочном файле. В случае глобальных объектов, по крайней мере, компоновщик в состоянии обнаружить наличие дублей. Но статические данные и функции могут дублироваться на законных основаниях, поскольку компилятор делает закрытую копию для каждого исходного файла. Так что если вы определите статические данные и статические функции в заголовочном файле и включите его в 50 файлов, то тела функций и пространство для данных в выходном исполняемом файле будут дублированы 50 раз (только если у вас не будет использован очень интеллектуальный компоновщик, который сможет распознать 50 одинаковых тел функций и наличие одинаковых константных данных, которые можно безопасно объединить). Излишне говорить, что глобальные данные (такие как статические >fudgeFactor
) на самом деле не являются глобальными объектами, поскольку каждый исходный файл работает со своей копией таких данных, независимой от всех остальных копий в программе.
Не пытайтесь обойти эту ситуацию при помощи использования безымянных пространств имен в заголовочных файлах, поскольку результат будет ничуть не лучше:
>// В заголовочном файле это приводит к тому же
>// эффекту, что и использование static
>namespace {
>int fudgeFactor;
>string hello("Hello, world!");
>void foo() { /* ... */ }
>}
В заголовочных файлах могут находиться следующие объекты с внешним связыванием.
• Встраиваемые функции. Они имеют внешнее связывание, но компоновщик гарантированно не отвергает многократные копии. Во всем остальном они ведут себя так же, как и обычные функции. В частности, адрес встраиваемой функции гарантированно будет единственным в пределах программы.
• Шаблоны функций. Аналогично встраиваемым функциям, инстанцирования ведут себя так же, как и обычные функции, с тем отличием, что их дубликаты приемлемы (и должны быть идентичны). Само собой разумеется, хороший компилятор устранит излишние копии.
• Статические данные-члены шаблонов классов. Они могут оказаться особенно сложными для компоновщика, но это уже не ваша проблема — вы просто определяете их в своем заголовочном файле и предоставляете сделать все остальное компилятору и компоновщику.
Кроме того, методика инициализации глобальных данных, известная как "Счетчики Шварца" ("Schwarz counters"), предписывает использование в заголовочном файле статических данных (или безымянных пространств имен). Джерри Шварц (Jerry Schwarz) использовал эту методику для инициализации стандартных потоков ввода-вывода