单例模式 (Singleton Pattern)

是什么,有什么用

一个类需要保证全局最多同时存在一个实例

有些东西需要保证全局只有一个,例如线程池、缓存、对话框。。。

要点

两种方法

  1. 懒汉式
    • 等到第一次实用的时候才实例化第一个实例
  2. 饿汉式
    • 加载类的时候就实例化第一个实例,之后都是调用
    • 缺点 - 没用到该类的时候就会占用系统资源(花时间实例化,占用系统空间),如果占用空间不大或者业务不在乎系统资源的话,可以使用
    • 优点 - 无线程安全问题

线程安全问题(仅针对懒汉式

实例化的时候,如果是多线程环境可能存在实例化多次的情况。

java可以通过 synchronized 或者 双重检验锁 的方法来解决

内存安全

防止内存泄漏

CPP实现

实现单例模式,需要

  1. 一个类静态变量,代表现在的状态,即现在是否存在单例
  2. 把构造函数放入private中,防止外部胡乱调用
  3. public中加入getInstance函数,以获取单例
    • 如果没实例,实例化一个
    • 返回唯一的实例

懒汉式(线程不安全)

  1. 线程安全问题
  2. 内存泄漏问题
// code1.
// .h
class Singleton{
private:
    static Singleton *unique;
    Singleton();
public:
    static Singleton *getInstance();
};

// .cpp
Singleton* Singleton::unique = nullptr; // 不写会寄
Singleton::Singleton(){};
Singleton* Singleton::getInstance(){
    if(unique ==nullptr)
        unique = new Singleton();
    return unique;
}

懒汉式(线程安全)

上一种在多线程环境下可能两个或者多个线程刚在 getInstance() 中的 if 判断环节通过后就切换线程,导致多次实例化

双重检验锁

与code1相比,需要加一个 private 锁变量,用于双重检验

// code2.
// .h
class Singleton{
private:
    static Singleton *unique;
    static std::mutex mutex_;	// #include <mutex>
    Singleton();
public:
    static Singleton *getInstance();
};
// .cpp
std::mutex Singleton::mutex_;
Singleton* Singleton::unique = nullptr;
Singleton::Singleton(){};
Singleton* Singleton::getInstance(){
    if(unique ==nullptr){
        mutex_.lock();
        if(unique ==nullptr){
            unique = new Singleton();
        }
        mutex_.unlock();
    }
    return unique;
}

饿汉式

线程安全:由于是加载时就声明了,不存在线程安全问题

内存安全:Singleton类里再定义一个类Gc,用Gc类的析构函数跟unique的内存回收进行绑定,然后Singleton类里弄一个静态Gc类小gc,这样小gc析构的时候,就可以在结束的时候完成垃圾回收。

//code3.
// .h
class Singleton{
public:
    static Singleton * getInstance();
    class Gc{
    public:
        ~Gc();
    };
private:
    static Singleton *unique;
    static Gc gc;
};


// .cpp
Singleton * Singleton::getInstance(){
    return unique;
}

Singleton::Gc::~Gc(){
    if (unique){
        delete unique;
    }
}

Singleton * Singleton::unique = new Singleton();
Singleton::Gc Singleton::gc;

参考

  1. 《大话设计模式》
  2. 《HeadFirst设计模式》
  3. c++单例模式

没看,以后万一学了java会看:
java单例模式

上一篇:实现数组去重的常用方法


下一篇:智能指针里的动态内存管理