C++单例模式

文章目录

1、什么是单例

单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例。

具体应用场景如:

  • 设备管理器。系统中可能有多个设备,但是只有一个设备管理器,用于管理设备驱动;

  • 数据池。用来缓存数据的数据结构,需要在一处写,多处读取或者多处写,多处读取。

2、一个好的单例应该具备的条件

  • 全局只有一个实例:static 特性,同时禁止用户自己声明并定义实例(把构造函数设为 private)
  • 用户通过接口获取实例:使用 static 类成员函数
  • 禁止赋值和拷贝
  • 线程安全

3、懒汉模式与饿汉模式

  • 懒汉模式:
    • 时间换空间;
    • 故名思义,不到万不得已就不会去实例化对象,在第一次用到类实例的时候才会去实例化对象;
    • 多线程情况下会存在线程安全问题,需要加互斥锁进行防护。
  • 饿汉模式:
    • 空间换时间;
    • 在单例类定义的时候就进行实例化对象,当需要使用时只要通过接口函数直接获取对象。

4、单例实现:线程安全、内存安全的懒汉式单例(基于C++11的智能指针和互斥锁)

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

class Singleton {
public:
    ~Singleton() {
        std::cout << "destructor called!" << std::endl;
    }
    Singleton(Singleton&) = delete;                  // copy constructor can't be called
    Singleton& operator=(const Singleton&) = delete; // assignment operator can't be called

    static std::shared_ptr<Singleton> getInstance() {
        // 双重锁检测
        if (m_pInstance == nullptr) {
            std::lock_guard<std::mutex> lk(m_mutex);

            if (m_pInstance == nullptr) {
                m_pInstance = std::shared_ptr<Singleton>(new Singleton);
            }
        }

        return m_pInstance;
    }

private:
    Singleton() {
        std::cout << "constructor called!" << std::endl;
    }

private:
    static std::shared_ptr<Singleton> m_pInstance;
    static std::mutex m_mutex;
};

// initialization static variables out of class
std::shared_ptr<Singleton> Singleton::m_pInstance = nullptr;
std::mutex Singleton::m_mutex;

int main() {
    std::shared_ptr<Singleton> instance1 = Singleton::getInstance();
    std::shared_ptr<Singleton> instance2 = Singleton::getInstance();
    
    return 0;
}

运行结果:

bash 复制代码
PS E:\Code\VSCode\Demo\build> ."E:/Code/VSCode/Demo/build/main.exe"
constructor called!
destructor called!
  • 基于 shared_ptr,用了C++比较倡导的 RAII 思想,即用对象管理资源。当 shared_ptr 析构的时候,new 出来的对象也会被 delete 掉,此避免内存泄漏。
  • 加了锁,使用互斥量来达到线程安全。这里使用了两个 if 判断语句的技术称为双检锁,其好处是,只有判断指针为空的时候才加锁,避免每次调用 get_instance 的方法都加锁,毕竟锁的开销还是有点大的。

不足之处在于: 使用智能指针会要求用户也得使用智能指针,非必要不应该提出这种约束;使用锁也有开销,并且在某些平台(与编译器和指令集架构有关),双检锁会失效!

相关推荐
郭涤生27 分钟前
std::async 和 std::future的使用
c++
墨韵流芳35 分钟前
CCF-CSP第41次认证第一题——平衡数
c++·算法·ccf·平衡数
水饺编程1 小时前
第4章,[标签 Win32] :SysMets3 程序讲解01
c语言·c++·windows·visual studio
砍光二叉树1 小时前
【设计模式】行为型-迭代器模式
设计模式·迭代器模式
郝学胜-神的一滴1 小时前
巧解括号序列分解问题:栈思想的轻量实现
开发语言·数据结构·c++·算法·面试
代码改善世界1 小时前
【C++初阶】string类(一):从基础到实战
开发语言·c++
计算机安禾1 小时前
【数据结构与算法】第15篇:队列(二):链式队列的实现与应用
c语言·开发语言·数据结构·c++·学习·算法·visual studio
迷途之人不知返1 小时前
初次学习模板
c++
程序猿追1 小时前
HarmonyOS 6.0 实战:用 Native C++ NDK 开发一款本地计步器应用
c++·华为·harmonyos
Q741_1472 小时前
每日一题 力扣 2840. 判断通过操作能否让字符串相等 II 力扣 2839. 判断通过操作能否让字符串相等 I 找规律 字符串 C++ 题解
c++·算法·leetcode·力扣·数组·找规律