设计模式:单例模式

本文深入探讨了单例模式的设计原则及实现方式,包括构造方法的屏蔽、唯一对象生成接口的设计等核心内容。同时,文章还介绍了如何解决多线程环境下单例模式的线程安全问题,并提供了两种不同的实现方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式:

1.构造,拷贝构造屏蔽起来
2.在类中提供一个接口 生成唯一对象
(1.不能返回类类型;2.不能依赖对象的调用)

#include<iostream>

using namespace std;

//校长类  
class Master
{
public:
	
	static Master *getInstance(char* name, int age)//摆脱于对对象的依赖
	{
		if (pma == NULL)
		{
			pma = new Master(name,age);
		}
		return pma;
	}
private:
	Master(char* name, int age) :mname(new char[strlen(name) + 1])
	{
		strcpy(mname, name);
		mage = age;
	}
	Master(const Master&);//声明而已
	//不会调用拷贝构造,因为拷贝构造是用一个已存在的对象来生成新对象
	char* mname;
	int mage;
	static Master* pma;//堆上
	//静态不属于对象所私有,是属于作用域的
};

Master* Master::pma = NULL;//静态成员需要在类外进行初始化

int main()
{
	Master* pma1 = Master::getInstance("zhangsan", 18);
	Master* pma2 = Master::getInstance("zhangsan", 18);
	Master* pma3 = Master::getInstance("zhangsan", 18);
	Master* pma4 = Master::getInstance("zhangsan", 18);
	return 0;
}

类中接口的返回值: 
Master 以类类型返回会生成临时对象 
Master*  Master& 返回指针、引用都可以

类中接口需要设置为静态:
普通成员方法: _thiscall调用约定,依赖于对象的调用
该接口是用来生成对象的,但该接口又依赖于对象的调用,无法使用
故为 static Master *getInstance(char* name, int age); //需摆脱于对对象的依赖

验证是同一个对象,调试结果:

                

从调试程序中可以看出,指针永远指向唯一的对象,因为整个类只能生成一个对象。

如果是多线程情况下,还会存在线程安全的问题:(假设有A、B两个线程)

         

假如A先进行到 if(psing==NULL)这步,判断条件为true,恰巧这时时间片到了,B运行这个程序,此时B也进行到这一步,判断条件为true,然后创建了一个对象,这时B时间片到了,轮到了A向下执行,此时因为A之前已经判断过,所以不再判断,接着上次继续向下执行,这样就会把psing指向B的指针断裂,会存在内存泄漏问题,并会生成两个对象,不满足单例模式。

解决方案:给临界区代码加锁

    static SingleTon * getIntance()
    {
        if(psing==NULL)
       {
            
//lock()
           if (psing == NULL)
           {
               psing = new SingleTon();
           }
         
   //unlock
       }
        return psing;
    }

这种模式叫做:双重锁机制的单例模式

此外,还有一种方式,即在进程开启之前,就已生成对象,这样便不会在这方面出现线程安全问题。

方案:在类中生成对象, 在 .data段,设置为静态 static

#include<iostream>

using namespace std;

class SingleTon
{
public:
	static SingleTon& getIntance()
	{
		return single;
	}
private:
	SingleTon(){}
	SingleTon(const SingleTon&);
	static SingleTon single;//生成的对象在 .data段
};

SingleTon SingleTon::single;//调用默认的构造函数,在main之前,对象就已生成

int main()
{
	//SingleTon single = SingleTon::getIntance();//报错,调用拷贝
	SingleTon& single = SingleTon::getIntance();
	return 0;
}

调试结果:

          

可以看出,single1还未生成,single已经生成。

          

接着single1才生成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值