c++设计模式(单例模式)

单例模式

  • 保证一个类只有一个实例,并提供一个访问它的全局访问点

    单例模式实际开发过程中使用频率还是挺高的,以前就那么用,只知道有懒汉式,饿汉式,也没有去深究,今天趁着学习设计模式,总结下。

    好,咱们直入正题,先来说说懒汉式

  • 懒汉式

    懒汉嘛,懒这个字就说明了你不去管他,他就不会动,放在单例模式里面,那就是:你不去调用他,他就不会去实例化那唯一的对象,示例代码如下:

class lazySingle
{
private:
	static lazySingle* la;
public:
	static lazySingle* GetSingle()
	{
		if(la == NULL)
			la = new lazySingle;
		return la;
	}
	void testFun()
	{
		cout << "This is a test fun" << endl;
	}
private:
	lazySingle() {}
	lazySingle(lazySingle &l) {}
	~lazySingle() {}
};
//在这里提醒下,一定记得初始化静态变量哦
lazySingle* lazySingle::la = NULL;

    这个办法有一个显而易见的问题,那就是线程不安全,具体的可以参考以下场景:

    有这么两个线程,线程中同时调用lazySingle::GetSingle()(假设在这之前没有任何人调用过这个函数)来获取单例模式中唯一的实例,第一个线程判断la==NULL,同时第二个线程也判断la==NULL,这个时候,两个线程得到的指针指向的并不是同一个实例,这也就违背了单例模式“保证一个类只存在一个实例”。

    解决的办法也有啊,线程安全首先想到的是互斥锁,那么加一把锁好了。

class lazySingle
{
private:
	static lazySingle* la;
        static mutex lock;//这把锁为什么是static呢?嗯...因为他要在static里面用啊
public:
	static lazySingle* GetSingle()
	{
        lock.lock();
		if(la == NULL)
			la = new lazySingle;
        lock.unlock();
		return la;
	}
	void testFun()
	{
		cout << "This is a test fun" << endl;
	}
private:
	lazySingle() {}
	lazySingle(lazySingle &l) {}
	~lazySingle() {}
};
lazySingle* lazySingle::la = NULL;
mutex lazySingle::lock;

    算是解决了问题了,可是好麻烦啊,有没有不需要考虑线程安全的单例模式?有!那就是饿汉式。顾名思义,饿汉式就是说,我怕饿,别管我现在用不用,你先把东西给我准备好。

  • 我的饿汉式1

    这是我第一次使用饿汉式写单例模式,当时也不是什么具体项目,就是自己写个demo练练手,那是怎么省事儿怎么来,网上一顿查(前后不超过五分钟),奥,原来这么写,简单,来呗。

class HungrySingleA
{
public:
    static HungrySingleA* GetSingle()
    {
        static HungrySingleA hu;
        return &hu;
    }
private:
    HungrySingleA()
    {
        cout << "HungrySingleA()" << endl;
    }
    HungrySingleA(HungrySingleA& h){}
    ~HungrySingleA(){}
};

    大致上就这么个模式,具体肯定没这么简单啦。看着没啥问题是吧?可是有一天我突然想到一个问题:

    静态局部变量在第一次调用的时候才进行初始化,那么如果两个线程同时调用(在此之前没有被调用过),这么时候是不是就会出现上述懒汉式会遇到的问题:得到两个不一样的实例?我不知道啊,这个时候只能感叹自己知识的匮乏,然后上网去找资料...

https://blog.csdn.net/imred/article/details/89069750

(这里面描述了一个有趣的现象:初始化时发生了对初始化的递归调用,说实话我不觉得谁会这么干...)

    这是我找到一篇博客,开头第一句:“在C++11标准中,要求局部静态变量初始化具有线程安全性”,看到这里我松了口气,剩下部分我都不需要去看了(感兴趣的可以看看),因为我现在大部分时候使用的正是c++11标准。可是,公司有很多老代码,他们的运行环境是vs2010甚至更低,他们不支持c++11,他还是线程安全的吗?那么好吧,为了安全,继续改造。

  • 我的饿汉式2

class HungrySingleB
{
public:
    static HungrySingleB* GetSingle()
    {
        return &hsb;
    }
private:
    HungrySingleB()
    {
        cout << "HungrySingleB()" << endl;
    }
    HungrySingleB(HungrySingleB& h){}
    ~HungrySingleB(){}

    static HungrySingleB hsb;
};
HungrySingleB HungrySingleB::hsb;

    这样在一开始单例模式中的“单例”在一开始就是存在的,不管谁去获取它,始终是那一个实例。

    基本单例模式就是这样了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值