C++ Dynamic Initialization | 'Dynamic Initialization' Guide

C++ Dynamic Initialization | 'Dynamic Initialization' Guide

이 글의 핵심

C++ Dynamic Initialization - "Dynamic Initialization" guide. Explains what is dynamic initialization?, static variable initialization, and practical examples with production code.

What is Dynamic Initialization?

Dynamic initialization is a method of initializing variables through function calls or expression evaluation at runtime. Used when value cannot be known at compile-time.

int getValue() { return 42; }

int x = getValue();  // Dynamic initialization (runtime)
constexpr int y = 42; // Constant initialization (compile-time)

Why needed?:

  • Flexibility: Initialize with runtime values (file, network, user input)
  • Complex logic: Complex initialization logic like constructors, function calls
  • Dependencies: Depend on other variables or external state

Here is a simple C++ code example. Try running the code directly to check its operation.

// When dynamic initialization is needed
int port = loadConfigFromFile();  // Read from file
std::string name = getUserInput();  // User input
Database db("localhost", port);  // Constructor call

Initialization Comparison:

Initialization MethodTimingExample
Constant initializationCompile-timeconstexpr int x = 10;
Dynamic initializationRuntimeint x = getValue();
Zero initializationProgram loadstatic int x;

Static Variable Initialization

Below is an implementation example using C++. Understand the role of each part while examining the code.

int compute() {
    return 42;
}

// Dynamic initialization
int global = compute();

void func() {
    static int local = compute();  // On first call
}

Static Variable Initialization Timing:

  1. Global variables: Initialized before main() execution
  2. Static local variables: Initialized on first call (lazy initialization)
#include <iostream>

int initGlobal() {
    std::cout << "Global variable initialization\n";
    return 100;
}

int global = initGlobal();  // Executed before main()

void func() {
    static int local = []() {
        std::cout << "Static local variable initialization\n";
        return 200;
    }();
}

int main() {
    std::cout << "main started\n";
    func();  // "Static local variable initialization"
    func();  // No output (already initialized)
}

// Output:
// Global variable initialization
// main started
// Static local variable initialization

Production Recommendation:

  • Global variables: Avoid if possible (initialization order problems)
  • Static local variables: Use for Singleton, lazy initialization

Practical Examples

Example 1: Static Local Variable

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.

class Database {
public:
    Database() {
        std::cout << "DB connection" << std::endl;
    }
};

Database& getDB() {
    static Database db;  // Initialize on first call
    return db;
}

int main() {
    getDB();  // "DB connection"
    getDB();  // No output (already initialized)
}

Example 2: Singleton

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.

class Singleton {
    Singleton() {
        std::cout << "Created" << std::endl;
    }
    
public:
    static Singleton& getInstance() {
        static Singleton instance;  // Thread-safe (C++11)
        return instance;
    }
};

int main() {
    auto& s1 = Singleton::getInstance();  // "Created"
    auto& s2 = Singleton::getInstance();  // No output
}

Example 3: Initialization Order Problem

Below is an implementation example using C++. Understand the role of each part while examining the code.

// file1.cpp
int x = compute1();

// file2.cpp
extern int x;
int y = x + 1;  // x may not be initialized yet

// ✅ Solve with static variable in function
int& getX() {
    static int x = compute1();
    return x;
}

int y = getX() + 1;  // Order guaranteed

Example 4: Lazy Initialization

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality and perform branching with conditionals. Understand the role of each part while examining the code.

class Resource {
public:
    Resource() {
        std::cout << "Resource created" << std::endl;
    }
};

Resource& getResource() {
    static Resource res;  // Created on first use
    return res;
}

int main() {
    const bool needResource = true;
    // Not created if Resource not used
    if (needResource) {
        getResource();
    }
}

Thread Safety

Below is an implementation example using C++. Try running the code directly to check its operation.

// C++11: Static local variable initialization is thread-safe
void func() {
    static int x = compute();  // Only one thread initializes
}

// C++03: Not thread-safe

C++11 Thread Safety Guarantee:

From C++11, static local variable initialization is automatically thread-safe. Compiler internally uses mutex to ensure only one thread initializes.

#include <thread>
#include <iostream>

int expensiveInit() {
    std::cout << "Init started (thread " << std::this_thread::get_id() << ")\n";
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Init completed\n";
    return 42;
}

void func() {
    static int value = expensiveInit();  // Thread-safe
    std::cout << "Value: " << value << '\n';
}

int main() {
    std::thread t1(func);
    std::thread t2(func);
    std::thread t3(func);
    
    t1.join();
    t2.join();
    t3.join();
}

// Output:
// Init started (thread ...)
// Init completed
// Value: 42
// Value: 42
// Value: 42
// (Initialization executed only once)

Summary

Key Points

  1. Dynamic initialization: Runtime initialization via function calls
  2. Global variables: Initialized before main()
  3. Static local variables: Lazy initialization on first call
  4. Thread safety: C++11 guarantees thread-safe static local initialization
  5. Order problems: Avoid global variable dependencies

When to Use

Use dynamic initialization when:

  • Need runtime values
  • Complex initialization logic
  • Lazy initialization (static local)
  • Singleton pattern

Don’t use when:

  • Can use constexpr (compile-time)
  • Global variable dependencies
  • Order-dependent initialization

Best Practices

  • ✅ Prefer static local variables over globals
  • ✅ Use for Singleton pattern
  • ✅ Leverage C++11 thread safety
  • ❌ Don’t create global variable dependencies
  • ❌ Don’t ignore initialization order

Master dynamic initialization for safer C++ code! 🚀