设计模式--单例(Singleton)模式


1 概念

单例模式(Singleton Pattern)是一种常见的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在C++中,单例模式通常用于管理全局资源提供全局配置



2 使用场景

以下是C++中实现单例模式的常见方法:


2.1 饿汉式单例模式

饿汉式是一种实现单例模式的策略,其特点是全局的单例实例在类装载时构建。这种方式的优点是类加载比较快,因为实例化工作在类加载时就已经完成。但缺点是如果该类从未被使用,则实例化会造成不必要的性能开销。

class Singleton {
public:
    static Singleton& getInstance() {
        // 在类加载时就完成了初始化,所以类加载比较频繁时可能会造成性能问题
        static Singleton instance;
        return instance;
    }
    
    // 其他成员函数...
    
private:
    Singleton() {}  // 私有构造函数,防止外部直接实例化
    Singleton(const Singleton&) = delete;  // 禁止拷贝构造函数
    Singleton& operator=(const Singleton&) = delete;  // 禁止拷贝赋值运算符
};


2.2 懒汉式单例模式

懒汉式是一种延迟加载的单例模式实现方式,其特点是在第一次使用时创建实例对象,而不是在类加载时就创建。这种方式的优点在于只有在真正需要时才会进行实例化,可以节省内存空间。但如果类被频繁地加载和卸载,懒汉式可能会造成不必要的性能开销。

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton* instance = nullptr;  // 延迟初始化
        if (instance == nullptr) {
            instance = new Singleton();  // 懒加载,只会在第一次调用时创建实例
        }
        return *instance;
    }
    
    // 其他成员函数...
    
private:
    Singleton() {}  // 私有构造函数,防止外部直接实例化
    Singleton(const Singleton&) = delete;  // 禁止拷贝构造函数
    Singleton& operator=(const Singleton&) = delete;  // 禁止拷贝赋值运算符
};


2.3 双重检查锁定(线程安全)

双重检查锁定(Double-Checked Locking)是一种在单例模式中使用的性能优化技术。这种技术旨在在并发环境下提高单例对象的创建效率,同时确保线程安全。
双重检查锁定的基本思想是在获取单例对象时进行双重检查,即先检查实例是否已经创建,如果尚未创建,再进行同步操作来确保只有一个线程创建实例。这样可以在不必要时避免同步开销,提高性能。这种技术在单例对象的初始化上实现了懒加载(Lazy Initialization),即对象直到第一次被访问时才进行初始化。
需要注意的是,在使用双重检查锁定时,需要特别注意内存模型的细节,以避免出现线程安全问题。例如,需要使用volatile关键字来确保对共享变量的正确读写,以及使用锁来保护临界区代码等。同时,由于双重检查锁定涉及到多线程编程的复杂性,因此在使用时需要谨慎处理线程同步和竞争条件的问题。
为了在多线程环境下安全地实现单例模式,可以使用双重检查锁定机制。在C++11及更高版本中,可以使用std::call_once来实现。以下是一个示例:

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton* instance = nullptr;  // 延迟初始化
        std::call_once(initInstanceFlag, &Singleton::initInstance);  // 使用std::call_once确保只初始化一次实例
        return *instance;
    }
    
    // 其他成员函数...
    
private:
    Singleton() {}  // 私有构造函数,防止外部直接实例化
    Singleton(const Singleton&) = delete;  // 禁止拷贝构造函数
    Singleton& operator=(const Singleton&) = delete;  // 禁止拷贝赋值运算符
    static void initInstance() { instance = new Singleton(); }  // 静态成员函数,用于初始化实例(只执行一次)
    static std::once_flag initInstanceFlag;  // 静态成员变量,用于控制初始化实例的执行次数(只执行一次)
};
posted @   guanyubo  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示