单例模式

前言:

  单例模式,顾名思义,只存在一个实例。官方定义:对于类的单例模式设计,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。

  单例模式在写法上有很多种,

有饿汉式(类加载的时候实例化),

懒汉式(类在使用的时候实例化),

保证线程安全的写法等。具体如下:(删除线表示不推荐使用)

    ① 饿汉式(静态常量)

    ② 饿汉式(静态代码块)

    ③ 懒汉式(线程不安全)

    ④ 懒汉式(线程安全,同步方法)

    ⑤ 懒汉式(线程安全,同步方法)

    ⑥ 双重检查double check

    ⑦ 静态内部类

    ⑧ 枚举

  在IOC模式中,通常使用生命周期来实现单例,如services.AddSingleton();

懒汉式

懒汉式(Lazy-Initialization)的方法是直到使用时才实例化对象,

也就说直到调用get_instance() 方法的时候才 new 一个单例的对象。

好处是如果被调用就不会占用内存。

class Singleton{
private:
    Singleton(){
        std::cout<<"constructor called!"<<std::endl;
    }
    Singleton(Singleton&)=delete;
    Singleton& operator=(const Singleton&)=delete;
    static Singleton* m_instance_ptr;
public:
    ~Singleton(){
        std::cout<<"destructor called!"<<std::endl;
    }
    static Singleton* get_instance(){
        if(m_instance_ptr==nullptr){
              m_instance_ptr = new Singleton;
        }
        return m_instance_ptr;
    }
    void use() const { std::cout << "in use" << std::endl; }
};

Singleton* Singleton::m_instance_ptr = nullptr;
    Singleton* instance = Singleton::get_instance();
    Singleton* instance_2 = Singleton::get_instance();
    return 0;
  1. 线程安全的问题,当多线程获取单例时有可能引发竞态条件:第一个线程在if中判断 m_instance_ptr是空的,于是开始实例化单例;同时第2个线程也尝试获取单例,这个时候判断m_instance_ptr还是空的,于是也开始实例化单例;这样就会实例化出两个对象,这就是线程安全问题的由来; 解决办法:加锁
  2. 内存泄漏. 注意到类中只负责new出对象,却没有负责delete对象,因此只有构造函数被调用,析构函数却没有被调用;因此会导致内存泄漏。解决办法: 使用共享指针;

线程安全、内存安全的懒汉式单例 (智能指针,锁)

class Singleton{
public:
    typedef std::shared_ptr<Singleton> Ptr;
    ~Singleton(){
        std::cout<<"destructor called!"<<std::endl;
    }
    Singleton(Singleton&)=delete;
    Singleton& operator=(const Singleton&)=delete;
    static Ptr get_instance(){

        // "double checked lock"
        if(m_instance_ptr==nullptr){
            std::lock_guard<std::mutex> lk(m_mutex);
            if(m_instance_ptr == nullptr){
              m_instance_ptr = std::shared_ptr<Singleton>(new Singleton);
            }
        }
        return m_instance_ptr;
    }


private:
    Singleton(){
        std::cout<<"constructor called!"<<std::endl;
    }
    static Ptr m_instance_ptr;
    static std::mutex m_mutex;
};
Singleton::Ptr Singleton::m_instance_ptr = nullptr;
std::mutex Singleton::m_mutex;
    Singleton::Ptr instance = Singleton::get_instance();
    Singleton::Ptr instance2 = Singleton::get_instance();

最推荐的懒汉式单例——局部静态变量

class Singleton
{
public:
    ~Singleton(){
        std::cout<<"destructor called!"<<std::endl;
    }
    Singleton(const Singleton&)=delete;
    Singleton& operator=(const Singleton&)=delete;
    static Singleton& get_instance(){
        static Singleton instance;
        return instance;

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

饿汉式

class Singleton {
public:
    static Singleton* getInstance()
    {
        return instance_;
    };

private:
    Singleton(){};
    Singleton(const Singleton&){};
    Singleton& operator=(const Singleton&){};

    static Singleton* instance_;
};

Singleton* Singleton::instance_ = new Singleton();