美文网首页
单例模式

单例模式

作者: 小幸运Q | 来源:发表于2021-04-23 14:52 被阅读0次

    • 单例类有一个静态单例类指针,在静态方法中new该指针实例化是懒汉,在单例类外部::初始化该指针是饿汉。

    保证一个类仅可以有一个实例化对象,并且提供一个可以访问它的全局接口。实现单例模式必须注意以下几点:

    1. 单例类只能由一个实例化对象。
    2. 单例类必须自己提供一个实例化对象。
    3. 单例类必须提供一个可以访问唯一实例化对象的接口。

    单例模式分为懒汉和饿汉两种实现方式。


    懒汉模式

    不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化一个对象。在访问量较小,甚至可能不会去访问的情况下,采用懒汉实现,这是以时间换空间。

    image.png

    非线程安全版:

    /*
    * 关键代码:构造函数是私有的,不能通过赋值运算,拷贝构造等方式实例化对象。
    */
    
    ​#include<iostream>
    using namespace std;
    //懒汉式一般实现:非线程安全,getInstance返回的实例指针需要delete
    class Singleton
    {
    public:
        static Singleton* getInstance();
        ~Singleton(){}
    ​
    private:
        Singleton(){}                                        //构造函数私有
        Singleton(const Singleton& obj) = delete;            //明确拒绝
        Singleton& operator=(const Singleton& obj) = delete; //明确拒绝
    
        static Singleton* m_pSingleton;
    };
    ​
    Singleton* Singleton::m_pSingleton = NULL;
    ​
    // 第一次访问getInstance才会new,并且要在private函数里
    Singleton* Singleton::getInstance()
    {
        if(m_pSingleton == NULL)
        {
            m_pSingleton = new Singleton;
        }
        return m_pSingleton;
    }
    
    int main(){
        // Singleton* s=new Singleton();  
        // 构造函数私有无法调用
        Singleton* s=Singleton::getInstance();
        s->print();
    }
    

    线程安全版:(双重检查)
    也可以先加锁然后检查一次,但是先检查可以避免已分配情况下的加锁操作,减小开销。

    std::mutex mt;
    
    class Singleton
    {
    public:
        static Singleton* getInstance();
    private:
        Singleton(){}                                    //构造函数私有
        Singleton(const Singleton&) = delete;            //明确拒绝
        Singleton& operator=(const Singleton&) = delete; //明确拒绝
    
        static Singleton* m_pSingleton;
    
    };
    Singleton* Singleton::m_pSingleton = NULL;
    
    Singleton* Singleton::getInstance()
    {
        if(m_pSingleton == NULL)
        {
            mt.lock();
            if(m_pSingleton == NULL)
            {
                m_pSingleton = new Singleton();
            }
            mt.unlock();
        }
        return m_pSingleton;
    }
    

    饿汉模式

    饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

    //饿汉式:线程安全,注意一定要在合适的地方去delete它
    class Singleton
    {
    public:
        static Singleton* getInstance();
    private:
        Singleton(){}                                    //构造函数私有
        Singleton(const Singleton&) = delete;            //明确拒绝
        Singleton& operator=(const Singleton&) = delete; //明确拒绝
    ​
        static Singleton* m_pSingleton;
    };
    ​
    Singleton* Singleton::m_pSingleton = new Singleton();
    ​
    Singleton* Singleton::getInstance()
    {
        return m_pSingleton;
    }
    

    最佳方案:

    使用静态局部变量

    class Single
    {
    
    public:
        // 获取单实例对象
        static Single &GetInstance();
        
        // 打印实例地址
        void Print();
    
    private:
        // 禁止外部构造
        Single();
    
        // 禁止外部析构
        ~Single();
    
        // 禁止外部复制构造
        Single(const Single &signal);
    
        // 禁止外部赋值操作
        const Single &operator=(const Single &signal);
    };
    
    Single &Single::GetInstance()
    {
        // 局部静态特性的方式实现单实例
        static Single signal;
        return signal;
    }
    

    相关文章

      网友评论

          本文标题:单例模式

          本文链接:https://www.haomeiwen.com/subject/cpcgyktx.html