单例模式之 懒汉和饿汉模式

单例模式是设计模式中比较简单的一种。适合于一个类只有一个实例的情况,比如窗口管理器,打印缓冲池和文件系统,它们都是原型的例子。典型的情况是,那些对象的类型被遍及一个软件系统的不同对象访问,因此需要一个全局的访问指针,这便是众所周知的单例模式的应用。

单例模式要保证的就是全局只有一个对象存在;所以很容易就能想到把构造析构定义为protected或者private,这样类外无法访问,就无法再定义对象了;
而懒汉和饿汉其本质也是这个样子,只是实现过程中有不一样而已;

懒汉模式

所谓的懒汉就是比较懒,我上来先不定义对象,在你要的时候我再去定义这个唯一对象,而之后来的只需要判断对象存不存在就好了;

class Singleton
    {
    public:
        static Singleton* GetInstance()
        {
                if (_inst == NULL)//判断不存在就定义
                {
                    Singleton* tmp = new Singleton;
                    _inst = tmp;
                }
            }

            return _inst;
        }

    private:
        Singleton()//造析构都定义为私有,类外无法再定义对象
        {}
        ~Singleton()
        {}

        //防拷贝
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);

        static Singleton* _inst;

    };

这样的代码在单线程下是没有任何问题的,但是一但放到多线程下,就会有问题,因为我们不能确保只有一个对象的基本原则了,所以必须要考虑的就是加锁,保证互斥,每次只有一个进程可以进来判断;

    static mutex _mtx;
            if (_inst == NULL)
            {
                lock_guard<mutex> lock(_mtx);//c11 lock_guard互斥自动上锁,lock_guard析构时,同时把互斥解锁。 
                if (_inst == NULL)
                {
                    Singleton* tmp = new Singleton;
                    _inst = tmp;
                }
            }

为了防止一个进程拿到锁之后出意外,跳出,所以我们给锁封装了一层RAII;

    class Lock
    {
    public:
        Lock(mutex& mtx)
            :_mtx(mtx)
        {
            _mtx.lock();
        }
        ~Lock()
        {
            _mtx.unlock();
        }
    protected:
        Lock(const Lock&);
        Lock& operator=(const Lock&);
    private:
        mutex& _mtx;
    };//设计RAII防止死锁

这样懒汉模式 就完成了;
懒汉总体代码

饿汉模式

饿汉模式就是我一上来就先定义好对象,你需要的时候我直接给你就好了,有了上面的懒汉模式,饿汉应该能更好理解,就是直接定义,你要的时候我给你就好了;

class Singleton
    {
    public:
        static Singleton& GetInstance()//直接返回给你就好
        {
            assert(_inst);
            return *_inst;
        }
    protected:
        Singleton()
            :_a(0)
        {}
        Singleton(const Singleton&);//一样的防拷贝
        Singleton& operator=(const Singleton&);

        static Singleton* _inst;

    };

    Singleton* Singleton::_inst = new Singleton;//一开始就定义

并且是线程安全的,因为全局就拿一份;
还有另外一种写法:

    class Singleton
    {
    public:
        static Singleton& GetInstance()
        {
            static Singleton inst;
            return inst;
        }
    protected:
        Singleton()
        {}
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);
    };

所以饿汉模式的多线程环境下是要比懒汉模式下方便许多的,但是具体应用场景还是要跟实际情况有关,
假如这个东西不是非必需的,那么就没有必要一上来就创建,完全可以等到需要的时候在创建,这样不至于浪费空间和性能;
所以各有优劣,具体情况具体分析;

懒汉代码

namespace LAZY//懒汉模式 需要的时候再定义
{
    //设计一个类为单例
    class Lock
    {
    public:
        Lock(mutex& mtx)
            :_mtx(mtx)
        {
            _mtx.lock();
        }
        ~Lock()
        {
            _mtx.unlock();
        }
    protected:
        Lock(const Lock&);
        Lock& operator=(const Lock&);
    private:
        mutex& _mtx;
    };//设计RAII防止死锁
    class Singleton
    {
    public:
        static Singleton* GetInstance()
        {
            if (_inst == NULL)
            {
                lock_guard<mutex> lock(_mtx);
                if (_inst == NULL)
                {
                    Singleton* tmp = new Singleton;
                    _inst = tmp;
                }
            }

            return _inst;
        }
        struct GC
        {
            ~GC()
            {
                DelInstance();
            }
        };
        static void DelInstance()
        {
            lock_guard<mutex> lock(_mtx);
            if (_inst)
            {
                cout << "delete" << endl;
                delete _inst;
                _inst = NULL;
            }
        }

    private:
        Singleton()//构造析构都定义为私有,类外无法再定义对象
        {}
        ~Singleton()
        {}

        //防拷贝
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);

        static Singleton* _inst;
        static mutex _mtx;
    };

    Singleton* Singleton::_inst = NULL;
    mutex Singleton::_mtx;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值