C++ Singleton 패턴

스레드 안전한 Singleton 구현입니다. Meyer's Singleton과 std::call_once 방식을 모두 포함하며, 복사/이동 생성자를 삭제하여 단일 인스턴스를 보장합니다.

Gist
#include <iostream>
#include <mutex>
#include <memory>
#include <string>

// ─────────────────────────────────────────────
// 방법 1: Meyer's Singleton (C++11 이후 스레드 안전 보장)
// 정적 지역 변수는 최초 호출 시 단 한 번만 초기화됨
// ─────────────────────────────────────────────
class ConfigManager {
public:
    // 유일한 인스턴스 접근점
    static ConfigManager& getInstance() {
        static ConfigManager instance;  // C++11: 스레드 안전 초기화
        return instance;
    }

    // 복사 생성자 및 복사 대입 연산자 삭제 → 복제 방지
    ConfigManager(const ConfigManager&) = delete;
    ConfigManager& operator=(const ConfigManager&) = delete;

    // 이동 생성자 및 이동 대입 연산자 삭제 → 이동 방지
    ConfigManager(ConfigManager&&) = delete;
    ConfigManager& operator=(ConfigManager&&) = delete;

    void set(const std::string& key, const std::string& value) {
        config_[key] = value;
    }

    std::string get(const std::string& key) const {
        auto it = config_.find(key);
        return (it != config_.end()) ? it->second : "";
    }

private:
    ConfigManager() {
        // 기본 설정값 초기화
        config_["version"] = "1.0.0";
        config_["env"]     = "production";
    }
    ~ConfigManager() = default;

    std::unordered_map<std::string, std::string> config_;
};

// ─────────────────────────────────────────────
// 방법 2: std::call_once 기반 Singleton
// 더 세밀한 초기화 제어가 필요할 때 사용
// ─────────────────────────────────────────────
class Logger {
public:
    static Logger& getInstance() {
        std::call_once(initFlag_, []() {
            instance_.reset(new Logger());  // 단 한 번만 실행
        });
        return *instance_;
    }

    Logger(const Logger&)            = delete;
    Logger& operator=(const Logger&) = delete;
    Logger(Logger&&)                 = delete;
    Logger& operator=(Logger&&)      = delete;

    void log(const std::string& message) const {
        std::cout << "[LOG] " << message << "\n";
    }

private:
    Logger()  { std::cout << "[Logger] 초기화 완료\n"; }
    ~Logger() = default;

    // 정적 멤버: 플래그와 인스턴스
    static std::once_flag          initFlag_;
    static std::unique_ptr<Logger> instance_;
};

// 정적 멤버 정의
std::once_flag          Logger::initFlag_;
std::unique_ptr<Logger> Logger::instance_;

// ─────────────────────────────────────────────
// 사용 예시
// ─────────────────────────────────────────────
int main() {
    // Meyer's Singleton 사용
    ConfigManager& cfg = ConfigManager::getInstance();
    cfg.set("db_host", "localhost");
    cfg.set("db_port", "5432");

    std::cout << "버전: "   << cfg.get("version") << "\n";
    std::cout << "DB 호스트: " << cfg.get("db_host") << "\n";
    std::cout << "DB 포트: "   << cfg.get("db_port") << "\n";

    // 동일 인스턴스 확인
    ConfigManager& cfg2 = ConfigManager::getInstance();
    std::cout << "동일 인스턴스 여부: "
              << (&cfg == &cfg2 ? "true" : "false") << "\n";

    // call_once 기반 Logger 사용
    Logger::getInstance().log("애플리케이션 시작");
    Logger::getInstance().log("설정 로드 완료");

    return 0;
}