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
Keywords
C++, zero initialization, static initialization, BSS, globals, static storage, initialization, memory
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Zero initialization sets storage to zero.
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- C++ Default Initialization | ‘기본 초기화’ 가이드
- C++ Aggregate Initialization | ‘집합체 초기화’ 가이드
- C++ Constant Initialization | ‘상수 초기화’ 가이드
Keywords Covered in This Article (Related Search Terms)
This article covers C++, zero initialization, static initialization, globals, BSS.