单例模式

本文深入分析并对比了四种常见的单例模式实现方式:基本实现、多线程安全实现、提前实例化实现和静态局部变量实现。详细解释了每种方法的原理、特点以及在不同场景下的应用,特别强调了多线程安全性和实例管理的重要性。同时,文章还讨论了每种实现方式的优缺点,并提出了在实际项目中如何避免内存泄露和资源未释放的问题,通过引入嵌套类Garbo来解决析构问题。

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

比较几种常见的单例模式实现

方法一:

#include<iostream>
using namespace std;
class Singleton
{
private:
	Singleton():Data(0)   //构造函数声明为私有
	{
	}
	static Singleton * Instance;
	
public:
	static Singleton & GetInstance();

	int Data;//用于测试
};
Singleton * Singleton::Instance=NULL;

Singleton & Singleton::GetInstance()
{
	if(Instance == NULL)  //判断是否实例已经存在
	{
		Instance = new Singleton();
	}
	return *Instance;
}

int main(void)
{
	Singleton& singletonObj1=Singleton::GetInstance();
	cout<<singletonObj1.Data<<endl;
	singletonObj1.Data=1;
	cout<<singletonObj1.Data<<endl;

	Singleton& singletonObj2=Singleton::GetInstance();
	cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
	singletonObj2.Data=2;
	cout<<singletonObj2.Data<<endl;
	return 0;
}

方法一是最基本的实现了单例模式。

方法二:

#include<iostream>
using namespace std;
class Singleton
{
private:
	Singleton():Data(0)   //构造函数声明为私有
	{
	}
	static Singleton * Instance;

public:
	static Singleton & GetInstance();

	int Data;//用于测试
};
Singleton * Singleton::Instance=NULL;

Singleton & Singleton::GetInstance()
{
	if(Instance == NULL)  //判断是否实例已经存在
	{
		lock();				//需要另外实现
		if (Instance==NULL)
		{
			Instance = new Singleton();
		}
		unlock();			//需要另外实现
		
	}
	return *Instance;
}

int main(void)
{
	Singleton& singletonObj1=Singleton::GetInstance();
	cout<<singletonObj1.Data<<endl;
	singletonObj1.Data=1;
	cout<<singletonObj1.Data<<endl;

	Singleton& singletonObj2=Singleton::GetInstance();
	cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
	singletonObj2.Data=2;
	cout<<singletonObj2.Data<<endl;
	return 0;
}

方法二相对于方法一,增加了多线程安全


方法三:

#include<iostream>
using namespace std;

class Singleton
{
private:
	Singleton():Data(0)   //构造函数声明为私有
	{
	}
	static Singleton * Instance;

public:
	static Singleton & GetInstance();

	int Data;//用于测试
};

Singleton * Singleton::Instance=new Singleton();

Singleton & Singleton::GetInstance()
{
	return *Instance;
}

int main(void)
{
	Singleton& singletonObj1=Singleton::GetInstance();
	cout<<singletonObj1.Data<<endl;
	singletonObj1.Data=1;
	cout<<singletonObj1.Data<<endl;

	Singleton& singletonObj2=Singleton::GetInstance();
	cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
	singletonObj2.Data=2;
	cout<<singletonObj2.Data<<endl;
	return 0;
}
方法三的实例在程序启动时就已经创建,因此在每次获取的时候就不需要进行任何的判断。


方法四:

#include<iostream>
using namespace std;

class Singleton
{
private:
	Singleton():Data(0)   //构造函数声明为私有
	{
	}
//	Singleton(const Singleton&);
//	Singleton& operator=(const Singleton&);

public:
	static Singleton & GetInstance();

	int Data;//用于测试
};

Singleton & Singleton::GetInstance()
{
	static Singleton Instance;
	return Instance;
}

int main(void)
{
	Singleton& singletonObj1=Singleton::GetInstance();
	cout<<singletonObj1.Data<<endl;
	singletonObj1.Data=1;
	cout<<singletonObj1.Data<<endl;

	Singleton& singletonObj2=Singleton::GetInstance();
	cout<<singletonObj2.Data<<endl;//通过观测此次输出的结果可知,singletonObj1与singletonObj2是同一对象
	singletonObj2.Data=2;
	cout<<singletonObj2.Data<<endl;

	return 0;
}
方法四将实例指定为静态局部变量,它是在第一次调用Singleton::GetInstance()时创建。其为局部静态变量,不是new出来的,在程序结束时能自动销毁,不用delete。但是其存在的一个问题就是,如果不是用引用调用此静态函数,而是Singleton singletonObj3=Singleton::GetInstance(),此句是调用复制构造函数,用GetInstance()返回的静态变量的值对singletonObj3对象初始化(此时在内存中有两个对象,静态对象和singletonObj3),为了防止此问题出现,应该也显示声明复制构造函数为私有。还有一个问题就是自我赋值,singletonObj1=singletonObj2,两者是同一个东西,为了防止此情况出现,我们可以在重载赋值操作中判断是否为同一个对象,但是单例模式中永远只有一个对象,那么我们干脆就显示声明赋值操作为私有既可。

即在类中把那两句注释消去,其实就是在编译中禁止了以上所说的两种操作,如果使用了,编译器会报错。


可以看出方法一、二、三都存在缺少delete的问题。

正常项目中,全局实例只有一个,在程序结束时,系统会释放内存资源,所以没有delete的问题并不大,不会发生内存泄露。但是在对象有 操作文件 或者 连接数据库 时,程序关闭时不会立即关闭资源,就需要在程序关闭前,手动释放资源。由于都是静态变量,因此不能使用类的析构函数对它进行销毁,有些人就想出了使用嵌套类专门处理释放资源。在方法一中加入嵌套类Garbo

class Singleton
{
private:
	Singleton():Data(0)   //构造函数声明为私有
	{
	}
	static Singleton * Instance;

public:
	static Singleton & GetInstance();

	int Data;//用于测试

	class Garbo //它的唯一工作就是在析构函数中删除CSingleton的实例

	{

	public:

		~Garbo()

		{

			if( Singleton::Instance )

				delete Singleton::Instance;
		}

	};

	static Garbo Garbo; //定义一个静态成员,程序结束时,系统会自动调用它的析构函数
};
Singleton * Singleton::Instance=NULL;

Singleton & Singleton::GetInstance()
{
	if(Instance == NULL)  //判断是否实例已经存在
	{
		Instance = new Singleton();
	}
	return *Instance;
}
需要更详细的内容可以参考 果冻想  http://www.jellythink.com/archives/82
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值