История вопроса
Статические члены классов появились в C++, чтобы позволить хранить общее для всех объектов значение или функцию, не привязанную к конкретному экземпляру класса. Это удобно для хранения, например, счётчиков, фабрик объектов или вспомогательных функций.
Проблема
Одной из сложностей всегда была область видимости и момент инициализации таких членов, особенно если в программе много исходных файлов. Неправильное определение static-члена приводит к ошибкам компоновки (linker errors).
Решение
В C++ static-члены объявляются в определении класса, но их инициализация (для переменных) должна происходить отдельно в cpp-файле (до C++17). C++17 позволяет инициализацию прямо внутри объявления, если это constexpr.
Пример кода:
class MyClass { public: static int counter; static void increment() { ++counter; } }; int MyClass::counter = 0; // инициализация ОБЯЗАТЕЛЬНА вне класса
Ключевые особенности:
Что произойдет, если не определить static-член в cpp-файле?
Получите ошибку компоновки (linker error), потому что статическая переменная будет объявленной, но не определённой. Исключение — если static const int инициализирован прямо внутри класса для constexpr-значения.
// .h class A { public: static int x; }; // .cpp // int A::x = 0; // если закомментировано — будет ошибка
Можно ли вызвать нестатическую функцию из статической?
Нет. Статической функции не доступен указатель this и нестатические члены напрямую. Для доступа нужен конкретный объект.
class B { int data; static void foo() { // data = 3; // ошибка } };
Являются ли статические переменные общими для всех экземпляров?
Да, в рамках одного исполняемого файла и процесса — одно и то же значение для всех экземпляров.
В команде забыли определить static-член в cpp-файле, проект периодически собирается с ошибкой, а иногда, при использовании inline-инициализации (не во всех компиляторах), появляется "таинственная" ошибка исполнения.
Плюсы:
Минусы:
В компании заведено правило: static-члены всегда определены в cpp-файлах для каждого класса. Для thread-safety используются std::mutex или атомарные операции.
Плюсы:
Минусы: