手撕单例模式中的饿汉模式和懒汉模式,懒汉模式还要再多加一个C++11版本的

以下展示 C++ 中单例模式的三种常见实现:饿汉模式、传统线程安全的懒汉模式(双重检查锁定) 以及 C++11 版本的懒汉模式(使用 Magic Static)。

cpp 复制代码
#include <iostream>
#include <mutex>

// ----------------------------- 1. 饿汉模式 -----------------------------
// 在程序启动时即完成实例创建,天然线程安全。
// 缺点:无论是否使用都会占用资源。
class SingletonHungry {
public:
    static SingletonHungry* getInstance() {
        return &instance;
    }

    // 禁止拷贝和赋值
    SingletonHungry(const SingletonHungry&) = delete;
    SingletonHungry& operator=(const SingletonHungry&) = delete;

private:
    SingletonHungry() { std::cout << "Hungry Singleton created." << std::endl; }
    static SingletonHungry instance;   // 静态实例,全局初始化
};

// 静态成员变量定义(程序启动时初始化)
SingletonHungry SingletonHungry::instance;


// ----------------------------- 2. 传统懒汉模式(双重检查锁定) -----------------------------
// 第一次使用时才创建实例,通过互斥锁保证线程安全。
// 注意:由于内存可见性问题,双重检查锁在早期 C++ 中可能失效,需配合原子操作。
// 这里使用 std::mutex 和双重检查作为示例。
class SingletonLazy {
public:
    static SingletonLazy* getInstance() {
        if (instance == nullptr) {               // 第一次检查
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {           // 第二次检查
                instance = new SingletonLazy();
            }
        }
        return instance;
    }

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

private:
    SingletonLazy() { std::cout << "Lazy Singleton (traditional) created." << std::endl; }
    static SingletonLazy* instance;
    static std::mutex mtx;
};

SingletonLazy* SingletonLazy::instance = nullptr;
std::mutex SingletonLazy::mtx;


// ----------------------------- 3. C++11 懒汉模式(Magic Static) -----------------------------
// 利用 C++11 标准保证:函数内静态局部变量的初始化是线程安全的。
// 代码最简洁,性能最优,推荐使用。
class SingletonCpp11 {
public:
    static SingletonCpp11& getInstance() {
        static SingletonCpp11 instance;   // 首次调用时初始化,C++11 保证线程安全
        return instance;
    }

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

private:
    SingletonCpp11() { std::cout << "Lazy Singleton (C++11) created." << std::endl; }
};


// ----------------------------- 测试代码 -----------------------------
int main() {
    std::cout << "=== 饿汉模式 ===" << std::endl;
    auto* hungry1 = SingletonHungry::getInstance();
    auto* hungry2 = SingletonHungry::getInstance();
    std::cout << "地址相同: " << (hungry1 == hungry2) << std::endl;

    std::cout << "\n=== 传统懒汉模式 ===" << std::endl;
    auto* lazy1 = SingletonLazy::getInstance();
    auto* lazy2 = SingletonLazy::getInstance();
    std::cout << "地址相同: " << (lazy1 == lazy2) << std::endl;

    std::cout << "\n=== C++11 懒汉模式 ===" << std::endl;
    auto& cpp111 = SingletonCpp11::getInstance();
    auto& cpp112 = SingletonCpp11::getInstance();
    std::cout << "地址相同: " << (&cpp111 == &cpp112) << std::endl;

    return 0;
}

关键说明

注意:C++11 标准规定:如果多个线程同时访问同一个函数内的静态局部变量,初始化过程是线程安全的,且只会执行一次。因此 static SingletonCpp11 instance; 是最推荐的现代 C++ 单例写法。

相关推荐
郑州光合科技余经理2 小时前
代驾系统架构拆解:订单链路、权限组织与私有化源码交付
开发语言·后端·算法·架构·系统架构·uni-app·php
码哥DFS5 小时前
二叉树的直径
开发语言·javascript·算法
paopaokaka_luck5 小时前
基于springboot3+vue3的企业考勤管理系统(部门树递归、Echarts图形化分析)
开发语言·spring boot·学习·echarts·mybatis·需求分析·代码规范
梦雨生生7 小时前
java开发工具(学习第一天)
java·开发语言·学习
啊啊啊啊啊!!!!8 小时前
【c++】stack和queue的接口使用以及底层实现
开发语言·c++
松仔log9 小时前
Java中级——组合和继承
android·java·开发语言
(Charon)11 小时前
【C++】锁与原子操作(四):自旋锁的完整实现与性能优化
c语言·开发语言·c++
雨田言炎11 小时前
五、Qt控件使用说明大全
开发语言·qt
ShineWinsu12 小时前
对于Linux:五种IO模型以及非阻塞IO的详细解析
linux·c++·面试·io·阻塞·非阻塞·fcntl
bu_shuo12 小时前
MATLAB中的meshgrid和ndgrid
开发语言·matlab