C++ Linkage and Storage Duration: extern, static, thread_local
이 글의 핵심
Linkage controls symbol visibility across translation units; storage duration controls object lifetime. Covers extern, static, thread_local, and initialization order pitfalls.
Linkage kinds
External linkage
Symbols visible to other translation units (e.g. non-inline int at namespace scope, non-static free functions).
// file1.cpp
int globalVar = 10;
void func() {
std::cout << globalVar << std::endl;
}
// file2.cpp
extern int globalVar;
extern void func();
int main() {
std::cout << globalVar << std::endl;
func();
}
Internal linkage
static at file scope, or anonymous namespaces—not visible to other TUs.
static int internalVar = 10;
static void internalFunc() {
std::cout << internalVar << std::endl;
}
No linkage
Local variables inside functions.
Storage duration
Automatic
Locals and parameters—destroyed at end of block.
Static
Globals, static locals, static class members—lifetime for entire program (or TU for internal linkage).
thread_local
Per-thread storage; each thread has its own instance.
Dynamic
new/delete (or smart pointers)—lifetime until explicitly freed.
extern usage
Variable declaration
// globals.cpp
int globalCounter = 0;
// main.cpp
extern int globalCounter;
const with extern
If you need shared const objects across TUs, use extern const consistently.
Explicit template instantiation (advanced)
Separate compilation patterns for templates may use extern template declarations—see your compiler docs.
static keyword
Function-local static
Initialized once, first time control passes through—thread-safe since C++11 for static locals.
Class static members
Declared in class; defined in one .cpp (or inline static in-class in C++17).
Common problems
Static initialization order fiasco
Avoid cross-TU initialization dependencies; prefer function-local statics for lazy init.
Duplicate definitions of globals
Only one definition across TUs for entities with external linkage.
thread_local cost
Each thread has its own copy—use for thread-local caches, RNG state, etc.
FAQ
Q1: extern vs static at file scope?
A: extern declares something defined elsewhere (often with external linkage). static at file scope gives internal linkage—not visible outside the TU.
Q2: When is thread_local useful?
A: Per-thread caches, per-thread PRNGs, TLS-style state.
Q3: Static initialization order?
A: Use function-local static for lazy initialization to avoid cross-TU ordering bugs.
Q4: Why extern “C”?
A: To link with C code by disabling C++ name mangling on those declarations.
Q5: Should I avoid globals?
A: Prefer narrower scope, dependency injection, or singletons where appropriate.
Q6: Further reading?
A: Stroustrup, cppreference, compiler manuals.
Related posts (internal links)
- C++ Extern Linkage
- C++ static members
- C++ Dynamic Initialization
Practical tips
Debugging
- Compiler warnings first.
- Minimal repro.
Performance
- Profile before optimizing.
Code review
- Follow team conventions.
Practical checklist
Before coding
- Right technique?
- Maintainable?
- Performance?
While coding
- Warnings fixed?
- Edge cases?
- Error handling?
During review
- Intent clear?
- Tests?
- Docs?
Keywords (search)
C++, linkage, storage, extern, static
Related posts
- C++ Extern Linkage
- C++ CRTP
- C++ Dynamic Initialization
- C++ static initialization order
- C++ Initialization Order