单例模式汇总篇

单例模式汇总

单例模式的几个深坑,你是已经否不知不觉地掉进去了:
  • 对象的析构问题
  • 线程安全
  • 一个单例类的构造函数调用另一个单例类
区分懒汉模式和饿汉模式:
  • 懒汉模式是指第一次使用的时候实例才会被构建,延迟加载,顾名思义,懒汉,特别懒,用到他,他才会加载。
  • 饿汉模式是指在类装载的时候就把单例实例构建好,顾名思义,饿汉,特别能吃,一上来就吃。

首先来看一下教科书式单例模式

class Singleton{
    public:
        static Singleton* GetInstance()
        {
            if(NULL==m_instance)
            {
                m_instance = new Singleton();
            }
            return m_instance;
        }
    private:
        Singleton(){
            std::cout<<"constructor has been called\n";
        }
        static Singleton* m_instance;
};
Singleton* Singleton::m_instance = NULL;

我们来看一下运行结果:
这里写图片描述
构造函数只调用了一次,这个单例模式好像是成功了,但是细心的同学们有没有发现,单例实例没有被正确的释放。什么时候释放,该怎么释放?最简单的方式是添加一个destory函数,在合适的地方调用。destory()如下:

static void destory()
{
    if(m_instance != NULL)
        delete m_instance;
}

但是缺陷很严重,大家很容易忘记调用他。最完美的方法是让这个类自己在合适的时机析构自己。当程序结束时,系统会为我们释放所有的全局变量以及静态变量,我们刚好可以利用这一点。下面是添加垃圾回收器的单例模式:

class Singleton
{
private:
    Singleton()
    {
        std::cout<<"constructor has been called\n";
    }
    static Singleton *m_instance;
    class GC   
    {
    public:
        GC()
        {
            std::cout<<"GC constructor has been called\n";
        }
        ~GC()
        {
            std::cout<<"GC desructor  has been called\n";
            if(Singleton::m_instance)
            {
                std::cout<<"delete m_instance\n";
                delete Singleton::m_instance;
            }
        }
    };
    static GC gc; //当gc被析构时,delete m_instance;
public:
    static Singleton * GetInstance()
    {
        if(m_instance == NULL)  
            m_instance = new Singleton();
        return m_instance;
    }
};

Singleton* Singleton::m_instance = NULL;
Singleton::GC Singleton::gc;

使用内嵌类GC实现了单例实例的自动释放,看起来已经不错了,但是我们不该满足于此。添加一个内嵌类让代码看起来一点儿都不优雅,添加内部类是为了解决对象的释放问题,还有什么能够实现自动释放呢,当然是牛x的智能指针了~~~,下面是智能指针版的单例模式:

class Singleton
{
public:
    static std::shared_ptr<Singleton> GetInstance()
    {
        if(m_instance == NULL)
            m_instance = std::shared_ptr<Singleton>(new Singleton);
        return m_instance;
    }
public:
    ~Singleton()//必须是public 由智能指针调用
    {
        std::cout<<"destructor has been called\n";
    }
private:
    static std::shared_ptr<Singleton> m_instance;
    Singleton()
    {
        std::cout<<"constructor has been called\n";
    }
};
std::shared_ptr<Singleton> Singleton::m_instance = NULL;

是不是清爽多了呀~~~,智能指针真乃C++程序员的一大利器,为智能指针歌功颂德的话不多说了,智能指针带来的便利,大家慢慢体会~
另外Meyers 大师在《More Effective C++》中给我们提供一种更牛掰的方法,也被称为Meyers Singleton。如下:

class Singleton
{
private:
    Singleton()
    {
        std::cout<<"constructor has been called\n";
    }
    ~Singleton()
    {
        std::cout<<"destructor has been called\n";
    }
    Singleton(const Singleton&);
    Singleton& operator(const Singleton&);
public:
    static Singleton& GetInstance()
    {
        static Singleton m_instance;   //局部静态变量
        return m_instance;
    }
};

Meyers 大师提供的这种方法代码量更少,真的是非常强大,但是需要注意的是返回一个对象的引用会出现类拷贝问题,例如Singleton single = Singleton::GetInstance;破坏了单例实例的全局唯一性,所以我们必须禁用类拷贝和赋值;也可以采用下面这种方式,返回对象的指针;

class Singleton
{
private:
    Singleton() 
    {
        std::cout<<"constructor has been called\n";
    }
    ~Singleton()
    {
        std::cout<<"destructor has been called\n";
    }
public:
    static Singleton * GetInstance()
    {
        static Singleton m_instance;   //局部静态变量
        return &m_instance;
    }
};

那么到这里我们是不是就该结束了呢? No No No,这才刚刚开始~,接下来我们聊聊开篇提到的三个大坑;
请看《单例模式汇总续》

ps:写下这篇博客的目的,其一是想体验下markdown,话说真心好使,给个赞~;其二是老师在讲C++,简直无聊~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值