• 单例模式(创建型设计模式)的 C++ 代码示例模板


    前言

    单例模式(创建型设计模式)的 C++ 代码示例模板。


    代码仓库


    单例模式(Singleton)

    结构

    • 单例类
    • 私有静态单例对象
    • 私有构造方法
    • 公有静态获取单例对象方法

    返回引用的原因:保证是同一单例对象而不是副本;减少返回值的拷贝开销;返回值拷贝被删除

    • 私有或删除拷贝构造方法和拷贝赋值运算符

    设置为私有:允许类内将单例对象作为参数或返回值传递(公有静态获取单例对象方法 可以返回值而不是引用)
    设置为删除:禁止拷贝
    设置为私有和删除:禁止拷贝

    核心

    • 私有静态单例对象:单例类内保存同一单例对象
    • 私有构造方法:禁止客户端创建多个单例对象
    • 公有静态获取单例对象方法:允许客户端创建或获取同一单例对象

    一般 饿汉式是获取,懒汉式是创建或获取。

    • 私有或删除拷贝构造方法和拷贝赋值运算符:禁止客户端或单例类内创建一个或多个拷贝单例对象

    类型

    • 饿汉式
    • 懒汉式

    饿汉式

    • 程序启动时(main() 执行前) 创建单例对象(不管用不用都提前创建)
    • 在类外初始化私有静态单例对象(保证在程序启动时(main() 执行前)创建单例对象)

    在类外初始化私有静态单例对象 注意:
    静态非 const 整数类型(short 和 int 等) 或 静态非 constexpr 内置类型(char 和 float 等)的成员属性 只能在类外初始化;
    因为构造方法是私有权限,所以在类外只能是隐式调用无参构造方法;
    如果单例类需要传参并初始化成员属性,可以考虑额外 定义设置成员属性方法 或 在公有静态获取单例对象方法中设置成员属性

    • 线程安全
    • 公有静态获取单例对象方法直接返回单例对象(因为在程序启动时(main() 执行前)已经创建单例对象,且线程安全,无需其他逻辑)
    • 创建或获取单例对象时使用引用

    使用引用的原因:保证是同一单例对象而不是副本;减少返回值的拷贝开销;返回值拷贝被删除

    代码

    // 饿汉式:程序启动时(main() 执行前) 创建单例对象(不管用不用都提前创建)
    #include 
    
    using std::cout;
    using std::endl;
    
    // 单例类
    class Singleton
    {
    public:
        ~Singleton() = default;
    
        // 公有静态获取单例对象方法
        inline static Singleton &getInstance() // 返回引用的原因:保证是同一单例对象而不是副本;减少返回值的拷贝开销;返回值拷贝被删除
        {
            return singleton; // 直接返回单例对象:因为在程序启动时(main() 执行前)已经创建单例对象,且线程安全,无需其他逻辑
        }
    
    private:
        // 私有构造方法
        Singleton()
        {
            cout << "Singleton()" << endl;
        }
    
        // 私有或删除拷贝构造方法和拷贝赋值运算符
        // 设置为私有:允许类内将单例对象作为参数或返回值传递(公有静态获取单例对象方法 可以返回值而不是引用)
        // 设置为删除:禁止拷贝
        // 设置为私有和删除:禁止拷贝
        Singleton(const Singleton &) = delete;
        Singleton &operator=(const Singleton &) = delete;
    
        // 私有静态单例对象
        static Singleton singleton;
    };
    
    // 在类外初始化私有静态单例对象 注意:
    // 静态非 const 整数类型(short 和 int 等) 或 静态非 constexpr 内置类型(char 和 float 等)的成员属性 只能在类外初始化
    // 因为构造方法是私有权限,所以在类外只能是隐式调用无参构造方法
    // 如果单例类需要传参并初始化成员属性,可以考虑额外 定义设置成员属性方法 或 在公有静态获取单例对象方法中设置成员属性
    Singleton Singleton::singleton; // 隐式调用无参构造方法
    
    // 客户端
    int main()
    {
        // 创建或获取单例对象
        Singleton &singleton_1 = Singleton::getInstance(); // 使用引用的原因:保证是同一单例对象而不是副本;减少返回值的拷贝开销;返回值拷贝被删除
        Singleton &singleton_2 = Singleton::getInstance();
    
        // 输出单例对象地址:地址相同,说明是同一单例对象
        cout << "Singleton_1: " << &singleton_1 << endl;
        cout << "Singleton_2: " << &singleton_2 << endl;
    
        return 0;
    }
    /*
    输出:
    Singleton()
    Singleton_1: 0x407030
    Singleton_2: 0x407030
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    懒汉式

    • 程序运行时创建单例类对象(需要用了才创建)
    • 在类外初始化私有静态单例对象 和 私有静态互斥锁(保证在程序运行时创建单例类对象)

    在类外初始化私有静态单例对象 和 私有静态互斥锁 注意:
    静态非 const 整数类型(short 和 int 等) 或 静态非 constexpr 内置类型(char 和 float 等)的成员属性 只能在类外初始化;
    因为构造方法是私有权限,所以在类外只能是隐式调用无参构造方法;
    如果单例类需要传参并初始化成员属性,可以考虑额外 定义设置成员属性方法 或 在公有静态获取单例对象方法中设置成员属性

    • 线程不安全(如多个线程同时调用公有静态获取单例对象方法)
    • 公有静态获取单例对象方法使用 私有静态互斥锁 和 双重检查锁定(保证线程安全)
    • 创建或获取单例对象时使用引用

    使用引用的原因:保证是同一单例对象而不是副本;减少返回值的拷贝开销;返回值拷贝被禁止

    代码(懒汉式)

    // 懒汉式:程序运行时创建单例类对象(需要用了才创建)
    #include 
    #include 
    #include 
    
    using std::cout;
    using std::endl;
    using std::lock_guard;
    using std::make_unique;
    using std::mutex;
    using std::unique_ptr;
    
    // 单例类
    class Singleton
    {
    public:
        ~Singleton() = default;
    
        // 公有静态获取单例对象方法
        static Singleton &getsingleton() // 返回引用的原因:保证是同一单例对象而不是副本;减少返回值的拷贝开销;返回值拷贝被删除
        {
            // 线程不安全(如多个线程同时调用公有静态获取单例对象方法)
            // 使用 私有静态互斥锁 和 双重检查锁定(保证线程安全)
            if (singleton == nullptr) // 第一重检查锁定
            {
                lock_guard<mutex> mutex_lock_guard(mutex_lock); // 上锁
    
                if (singleton == nullptr) // 第二重检查锁定
                {
                    // make_unique<> 是非成员函数模板,不是类的成员,即使在类内也不能访问类内私有成员,需要声明为友元
                    singleton = make_unique<Singleton>();
                }
    
                // 隐式解锁
            }
    
            return *singleton;
        }
    
    private:
        // 私有构造方法
        Singleton()
        {
            cout << "Singleton()" << endl;
        }
    
        // 私有或删除拷贝构造方法和拷贝赋值运算符
        // 设置为私有:允许类内将单例对象作为参数或返回值传递(公有静态获取单例对象方法 可以返回值而不是引用)
        // 设置为删除:禁止拷贝
        // 设置为私有和删除:禁止拷贝
        Singleton(const Singleton &) = delete;
        Singleton &operator=(const Singleton &) = delete;
    
        // 私有静态单例对象
        static unique_ptr<Singleton> singleton;
    
        // 私有静态互斥锁
        static mutex mutex_lock;
    
        // 声明 make_unique<> 为友元
        friend unique_ptr<Singleton> make_unique<Singleton>();
    };
    
    // 在类外初始化私有静态单例对象为空 和 私有静态互斥锁 注意:
    // 静态非 const 整数类型(short 和 int 等) 或 静态非 constexpr 内置类型(char 和 float 等)的成员属性 只能在类外初始化
    // 因为构造方法是私有权限,所以在类外只能是隐式调用无参构造方法
    // 如果单例类需要传参并初始化成员属性,可以考虑额外 定义设置成员属性方法 或 在公有静态获取单例对象方法中设置成员属性
    unique_ptr<Singleton> Singleton::singleton = nullptr;
    mutex Singleton::mutex_lock;
    
    // 客户端
    int main()
    {
        // 创建或获取单例对象
        Singleton &singleton_1 = Singleton::getsingleton(); // 使用引用的原因:保证是同一单例对象而不是副本;减少返回值的拷贝开销;返回值拷贝被禁止
        Singleton &singleton_2 = Singleton::getsingleton();
    
        // 输出单例对象地址:地址相同,说明是同一单例对象
        std::cout << "Singleton_1: " << &singleton_1 << std::endl;
        std::cout << "Singleton_2: " << &singleton_2 << std::endl;
    
        return 0;
    }
    /*
    输出:
    Singleton()
    Singleton_1: 0x25624e0
    Singleton_2: 0x25624e0
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    总结

    单例模式(创建型设计模式)的 C++ 代码示例模板。


    参考资料


    作者的话

    • 感谢参考资料的作者/博主
    • 作者:夜悊
    • 版权所有,转载请注明出处,谢谢~
    • 如果文章对你有帮助,请点个赞或加个粉丝吧,你的支持就是作者的动力~
    • 文章在描述时有疑惑的地方,请留言,定会一一耐心讨论、解答
    • 文章在认识上有错误的地方, 敬请批评指正
    • 望读者们都能有所收获

  • 相关阅读:
    【知识】超详细! 论文相关知识科普大全
    Anaconda虚拟环境下导入opencv
    项目管理必备工具推荐:提高效率、协作与跟踪的实用工具盘点
    河北吉力宝以步力宝健康鞋引发的全新生活生态商
    OpenCV 透视变换
    TensorFlow搭建LSTM实现时间序列预测(负荷预测)
    【PMTU】TCP的MTU探测
    【BOOST C++ 5 】通信(04 协程 )
    cartographer中创建轨迹
    java并发编程 CyclicBarrier详解
  • 原文地址:https://blog.csdn.net/m0_62083249/article/details/134515065