Static Members
A static member belongs to the class itself, not to any object: one shared variable or a function with no this-pointer, accessed as Class::member.
Why it matters
Static data is the idiomatic place for per-class shared state — an instance counter, a config singleton, a cached lookup table — without a global variable polluting the namespace. Static functions are factories and helpers that conceptually belong to the type but need no object. The C++17 inline keyword finally let you define a static member entirely in a header, removing decades of “undefined reference” friction.
How it works
There is exactly one copy of a static data member for the whole program; static functions can be called with no instance.
- Definition rule (pre-C++17): a non-
conststatic member needs a separate out-of-class definition in one.cpp, or the linker errors.inline static(C++17) orstatic constexprdefines it in-class — no.cppline. - Static functions have no
this, so they cannot read non-static members but can accessprivatestatics of the class. - Initialization across translation units is unordered — the “static initialization order fiasco”; defer with a function-local static (Meyers singleton) which inits on first use, thread-safely since C++11.
- A
static constexprmember is a compile-time constant usable in array bounds and templates.
Example
struct Widget {
inline static int count = 0; // C++17: defined here, no .cpp needed
Widget() { ++count; }
~Widget() { --count; }
static int alive() { return count; } // no 'this'
};
Widget a, b;
int n = Widget::alive(); // 2 — class-scoped callcount is shared: both objects increment the single variable; alive() reads it without an instance.
Pitfalls
- Static init order fiasco: one global static using another from a different
.cppmay see it un-initialized; use a function-local static instead. - Forgetting the out-of-class definition of a non-
inlinestatic yields a link-time “undefined reference”, not a compile error. - Static members are shared across threads — increments need atomics or a mutex to avoid data races (memory-model-data-races).
- Calling a static function via an instance (
obj.alive()) compiles but misleads readers; preferWidget::alive().