Используйте анонимные пространства имен
По умолчанию все глобальные переменные (не константы) и свободные функции получают внешнее связывание (external linkage) и их имена видны компоновщику. Одинаковые имена в разных модулях вызывают ошибки компоновщика. До введения С++11 для избежания коллизий имен из разных модулей использовалось ключевое слово static, которое делало имя "невидимым" за пределами модуля.
Пример:
static слишком перегружен и используется в разных контекстах:
- Локальные статические переменные внутри функций.
- Статические члены класса.
- Статические глобальные переменные/функции.
В С++11 ввели анонимные пространства, который заменил сишный подход родным механизмом С++ - пространства имен.
Пример:
Анонимные пространства позволяют также скрывать типы (классы, структуры, перечисления)
namespace {
class ParserStateMachine {
// ...
};
// Теперь этот класс не виден в других единицах трансляции
}
Важно! Анонимные пространства имен не отменяют внешнее связывание, но добавляют сущностям уникальное, сгенерированное компилятором имя, которое гарантированно не пересекается с именами из других единиц трансляции.
Не используйте анонимные пространства в заголовочных файлах!
Это создает серьезные проблемы с ODR (One Definition Rule) и раздуванием кода.
Неправильно:
// Utils.h
namespace {
int internalCounter = 0;
inline void incrementCounter() { internalCounter++; }
}
Допустим, есть два исходных файла, которые подключают Utils.h: file1.cpp и file2.cpp.
После препроцессинга в каждом .cpp файле будет объявлено свое собственное, абсолютно независимое безымянное пространство имен.
Если идея заключалась в единой глобальной переменной, то вызов incrementCounter() в одном модуле изменит только переменную из этого модуля и накак не повиляет на ее копию в другом.