C++ Zero Initialization | The 'All Bits Zero' First Step
이 글의 핵심
Zero initialization sets storage to zero. Static and thread-local objects get it before dynamic init; locals do not unless you value-initialize. Relation to value and default init.
What is zero initialization?
Zero initialization sets the object’s initial value to zero (or null pointer / false as appropriate). Static storage duration objects get it automatically before dynamic initialization. For automatic locals, use T{} or value initialization—do not wait for zero init.
Here is the 0 implementation:
int global; // 0 (static duration → zero-initialized)
static int s; // 0 (static → zero-initialized)
void func() {
static int x; // 0 (static → zero-initialized)
int y; // ❌ indeterminate (automatic → NOT zero-initialized)
int z{}; // ✅ 0 (value-initialized)
}
Zero initialization results by type
| Type | Zero-init result | Example |
|---|---|---|
| Integer types | 0 | int x; → 0 (if static) |
| Floating-point | +0.0 | double d; → 0.0 (if static) |
bool | false | bool b; → false (if static) |
| Pointers | null pointer value | int* p; → nullptr (if static) |
| Arrays | Each element zero-initialized | int arr[5]; → {0,0,0,0,0} (if static) |
| Class types | Recursively zero-init members | Then constructors run |
Who gets zero initialization automatically?
Static storage duration
// Namespace scope
int globalVar; // Zero-initialized before main()
// Static local
void func() {
static int counter; // Zero-initialized on first call
}
// Static member
class MyClass {
static int count; // Zero-initialized before main()
};
int MyClass::count;
Thread-local storage
thread_local int threadVar; // Zero-initialized per thread
void func() {
thread_local int localThreadVar; // Zero-initialized per thread
}
Initialization phases for static objects
Static initialization happens in stages:
- Zero initialization — All bits set to zero
- Constant initialization —
constexpr/ compile-time constants - Dynamic initialization — Runtime constructors before
main()
Here is the compute implementation:
int g1; // 1. Zero-init → 0
constexpr int g2 = 50; // 2. Constant-init → 50
int g3 = compute(); // 3. Dynamic-init (runtime)
int compute() {
return 42;
}
Locals vs static: Critical difference
#include <iostream>
int g; // Static duration → zero-initialized
void test() {
static int s; // Static duration → zero-initialized
int a; // Automatic → NOT zero-initialized (indeterminate!)
int b{}; // Automatic → value-initialized (zero)
std::cout << "g = " << g << "\n"; // 0
std::cout << "s = " << s << "\n"; // 0
// std::cout << "a = " << a << "\n"; // ❌ UB: reading indeterminate value
std::cout << "b = " << b << "\n"; // 0
}
Common mistake: Assuming locals are “almost zero” like globals—they are not!
Real-world examples
1. Global counters
// Automatically zero-initialized
int requestCount;
int errorCount;
void handleRequest() {
++requestCount;
if (error) {
++errorCount;
}
}
// Safe to use without explicit initialization
2. Static lookup tables
Here is the countCharacters implementation:
// Zero-initialized before main()
int frequencyTable[256];
void countCharacters(const std::string& text) {
for (char c : text) {
++frequencyTable[static_cast<unsigned char>(c)];
}
}
3. Singleton pattern
class Logger {
static Logger* instance;
public:
static Logger& getInstance() {
if (!instance) { // instance is nullptr (zero-initialized)
instance = new Logger();
}
return *instance;
}
};
Logger* Logger::instance; // Zero-initialized to nullptr
Classes and zero initialization
Trivial types
struct Point {
int x;
int y;
};
Point globalPoint; // Zero-initialized: {0, 0}
void func() {
Point localPoint; // ❌ NOT zero-initialized (indeterminate)
Point valuePoint{}; // ✅ Zero-initialized: {0, 0}
}
Non-trivial types
class Widget {
int value_;
public:
Widget() : value_(42) {} // Constructor runs after zero-init
};
Widget globalWidget; // 1. Zero-init, 2. Constructor → value_ = 42
void func() {
static Widget staticWidget; // 1. Zero-init, 2. Constructor
Widget localWidget; // Just constructor (no zero-init first)
}
Common mistakes
Mistake 1: Expecting locals to be zero
void badFunction() {
int sum; // ❌ NOT zero! Indeterminate value
for (int i = 0; i < 10; ++i) {
sum += i; // ❌ UB: using indeterminate value
}
}
// ✅ Fix
void goodFunction() {
int sum = 0; // Explicit initialization
for (int i = 0; i < 10; ++i) {
sum += i;
}
}
Mistake 2: Relying on zero for non-trivial types
struct Data {
std::string name; // Non-trivial
int count;
};
Data globalData; // Zero-init doesn't make name = "" directly
// name's constructor runs after zero-init
void func() {
Data localData; // ❌ count is indeterminate!
Data valueData{}; // ✅ Both members properly initialized
}
Mistake 3: Using memset on non-trivial types
struct Widget {
std::string name;
int value;
};
Widget w;
// ❌ WRONG: Destroys std::string's internal state
memset(&w, 0, sizeof(w));
// ✅ Correct: Use value initialization or assignment
Widget w{}; // or
w = Widget{};
Zero initialization vs value initialization
| Initialization | Syntax | Static objects | Local objects |
|---|---|---|---|
| Zero | int x; (static) | ✅ Zero | ❌ Indeterminate |
| Value | int x{}; | ✅ Zero | ✅ Zero |
| Default | int x; (local) | ✅ Zero first | ❌ Indeterminate |
Here is the func implementation:
// Static storage
int g1; // Zero-init → 0
int g2{}; // Value-init (includes zero) → 0
void func() {
// Automatic storage
int a; // Default-init → indeterminate ❌
int b{}; // Value-init → 0 ✅
}
BSS segment
BSS (Block Started by Symbol): Uninitialized data segment where zero-initialized globals live.
Here is the main implementation:
int globalArray[1000000]; // 4MB in BSS (not in executable file)
int main() {
// globalArray is zero-initialized at program start
// No 4MB added to executable size!
}
Benefit: Large zero-initialized arrays don’t bloat executable size.
Static initialization order fiasco
Here is the computeValue implementation:
// file1.cpp
int computeValue() { return 42; }
int value1 = computeValue(); // Dynamic init
// file2.cpp
extern int value1;
int value2 = value1 * 2; // ⚠️ Order undefined across TUs!
// If value2 initializes first, value1 is still zero!
Solution: Use function-local statics or constexpr:
The following example demonstrates the concept in cpp:
// file1.cpp
constexpr int value1 = 42; // Constant init (safe)
// Or
int& getValue1() {
static int value = 42; // Initialized on first call
return value;
}
Performance implications
Zero cost: Zero initialization of static objects happens before main() and is typically free (BSS segment).
Here is the func implementation:
// No runtime cost
int largeArray[1000000]; // BSS segment, zero at load time
// Runtime cost
void func() {
int largeArray[1000000]{}; // Stack allocation + zero-fill
}
Debugging zero initialization
Check if variable is zero-initialized
#include <iostream>
#include <type_traits>
template<typename T>
void checkInit() {
if constexpr (std::is_trivially_default_constructible_v<T>) {
std::cout << "Trivial: static objects zero-initialized\n";
} else {
std::cout << "Non-trivial: constructor runs\n";
}
}
checkInit<int>(); // Trivial
checkInit<std::string>(); // Non-trivial
Compiler support
| Compiler | Zero initialization | BSS optimization |
|---|---|---|
| GCC | All versions | Yes |
| Clang | All versions | Yes |
| MSVC | All versions | Yes |
Related posts
- C++ Value initialization
- C++ Default initialization
- C++ Constant initialization
- C++ Initialization order
- [C++ Static initialization order fiasco](/en/blog/cpp-constant-initialization/
Keywords
C++, zero initialization, static initialization, BSS, globals, static storage, initialization, memory
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Zero initialization sets storage to zero. Static and thread-local objects get it before dynamic init; locals do not unle… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ Default Initialization | ‘기본 초기화’ 가이드
- C++ Aggregate Initialization | ‘집합체 초기화’ 가이드
- C++ Constant Initialization | ‘상수 초기화’ 가이드
이 글에서 다루는 키워드 (관련 검색어)
C++, zero initialization, static initialization, globals, BSS 등으로 검색하시면 이 글이 도움이 됩니다.