单例模式-Singleton

摘要:今天看面试会问到单例模式,今天我们就来学习一下。

介绍

  意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  主要解决:一个全局使用的类的频繁地创建与销毁。

  使用场景:当想控制实例数目,节省资源的时候。

  关键代码:构造函数是私有的;拷贝构造函数是私有的;局部变量是静态的。

实现

  不支持并发

/*
 * method-1
 * 延迟初始化,只有在第一次调用 getInstance 的时候才会初始化实例
 * 存在问题:线程不安全版本,可能有多个线程在 if 条件处产生竞态条件,从而产生多个实例
 * */
class Singleton {
public:
    static Singleton* getInstance() {
        //先检查对象是否存在
        if(m_instance == nullptr) {
            m_instance = new Singleton();
        }
        return m_instance;
    }
private:
    //构造函数私有化
    Singleton();
    //析构函数私有化
    ~Singleton();
    //拷贝构造函数私有化
    Singleton(const Singleton& other);
    //赋值函数私有化
    Singleton& operator = (const Singleton &);
    //静态局部变量
    static Singleton* m_instance;
};

//静态成员需要在类外赋值
Singleton* Singleton::m_instance = nullptr;

  支持并发[加锁]

/*
 * method-2
 * 线程安全版本
 * 存在问题:但锁的代价过高
 * */
class Singleton {
public:
    static Singleton* getInstance() {
        Lock lock; //加锁,此处为伪代码
        if(m_instance == nullptr) {
            m_instance = new Singleton();
        }
        unlock;
        return m_instance;
    }
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton& other);
    Singleton& operator = (const Singleton &);
    static Singleton* m_instance;
};

//静态成员需要在类外赋值
Singleton* Singleton::m_instance = nullptr;

  双检查锁

/*
 * method-3
 * 线程安全版本,双检查锁
 * 存在问题:产生内存读写乱序问题
 * 分析:实际上 m_instance = new Singleton() 这条语句是分三个步骤来执行的
 * (1) 分配了一个 Sington 类型对象所需要的内存
 * (2) 再分配的内存出构造 Singleton 类型的对象
 * (3) 把分配的内存地址赋给指针 m_instance
 * 编译器会给我们做些优化,其实这三个步骤不一定是顺序执行的,只能确定步骤(1) 是最先执行的,步骤(2)(3) 却不一定。
 * 如果线程 A 在调用执行 m_instance = new Singleton() 的时候是按照 (1)(3)(2)的顺序执行的,那么刚刚执行完(3)给 m_instance 分配了内存
 * 此时 m_instance 就不再是 nullptr
 * 如果此时切换到了线程B, 由于 m_instance != nullptr, 所以线程B会直接执行 return m_instance 得到一个对象,而这个对象并没有被真正构造
 * 解决方式:在声明 m_instance 变量的时候,要加上 volatile 关键字修饰
 * */
class Singleton {
public:
    Singleton* getInstance() {
        if(m_instance == nullptr) {
            Lock lock;
            if(m_instance == nullptr) {
                m_instance = new Singleton();
            }
            unlock;
        }
    }

private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton& other);
    Singleton& operator = (const Singleton &);
    static Singleton* m_instance;
};

//静态成员需要在类外赋值
Singleton* Singleton::m_instance = nullptr;

  C++11 极简实现

/*
 * method-4
 * 最为简单的实现方式
 * 存在问题:C++11及以后的版本下才正确,之前的版本不能这么写,原因是 C++11 在底层可以保证 static 变量是多线程安全的
 * */
class Singleton {
public:
    Singleton* getInstance() {
        static Singleton instance;
        return &instance;
    }
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton& other);
    Singleton& operator = (const Singleton &);
};

 

posted on 2020-07-02 20:10  爱笑的张飞  阅读(230)  评论(0编辑  收藏  举报

导航