Используйте анонимные пространства имен

По умолчанию все глобальные переменные (не константы) и свободные функции получают внешнее связывание (external linkage) и их имена видны компоновщику. Одинаковые имена в разных модулях вызывают ошибки компоновщика. До введения С++11 для избежания коллизий имен из разных модулей использовалось ключевое слово static, которое делало имя "невидимым" за пределами модуля.

Пример:

// Файл .cpp (C++98)
static int localCounter = 0;
static void MyFunction() { /* ... */ }

static слишком перегружен и используется в разных контекстах:

  • Локальные статические переменные внутри функций.
  • Статические члены класса.
  • Статические глобальные переменные/функции.

В С++11 ввели анонимные пространства, который заменил сишный подход родным механизмом С++ - пространства имен.

Пример:

// Файл .cpp (C++11+)
namespace {
    int localCounter = 0;
    void helperFunction() { /* ... */ }
}

Анонимные пространства позволяют также скрывать типы (классы, структуры, перечисления)

namespace {
    class ParserStateMachine {
        // ...
    };
    // Теперь этот класс не виден в других единицах трансляции
}

Важно! Анонимные пространства имен не отменяют внешнее связывание, но добавляют сущностям уникальное, сгенерированное компилятором имя, которое гарантированно не пересекается с именами из других единиц трансляции.

Не используйте анонимные пространства в заголовочных файлах!

Это создает серьезные проблемы с ODR (One Definition Rule) и раздуванием кода.

Неправильно:

// Utils.h
namespace {
    int internalCounter = 0;
    inline void incrementCounter() { internalCounter++; }
}

Допустим, есть два исходных файла, которые подключают Utils.hfile1.cpp и file2.cpp.

После препроцессинга в каждом .cpp файле будет объявлено свое собственное, абсолютно независимое безымянное пространство имен.

Если идея заключалась в единой глобальной переменной, то вызов incrementCounter() в одном модуле изменит только переменную из этого модуля и накак не повиляет на ее копию в другом.