在实际开发中,我们往往需要一个类只能被实例化一次,如果有多个对象的话,就会导致混乱情况发生。

优点

一、实例控制

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

二、灵活性

因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点


一、开销

虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

二、可能的开发混淆

使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

三、对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。。

今天我们就来实现以下三个单例模式

1.懒汉式

class test
{
public:
	static test * gettest()
	{
		if (p == NULL)
			p = new test();
		return p;
	}
private:
	test() {};
	static test*p;

};



我们将类的构造函数声明为私有的,这样就不能通过构造函数来创建类对象,定义一个静态的gettest()函数来创建获取类资源,而这个函数不需要创建类对象,只需要通过类名访问即可。只有在第一次创建类对象时,资源进行了分配,其余时候不进行分配。这样就实现了一个类只有一个实例的要求。



缺点:存在内存泄露。new出来的东西始终没有释放。



2.饿汉式



class test {

private:
	static test* p;
	test();
	class test2 {
	public:
		~test2()
		{
			if (test::p)
			{
				delete test::p;
			}
		}
	};
	static test2 t;
public:
	static test* gettest()
	{
		if (p == NULL)
		{
			p = new test();
			return p;
		}
	}
};



这里采用一种内嵌定义的方式,定义一个test2类,专门只做一件事,就是用来释放new出来的资源,当程序运行结束时,系统会自动析构所有的全局变量。会自动调用test2的析构函数,把p的资源释放。



饿汉式的特点是一开始就加载了,如果说懒汉式是时间换空间,那么饿汉式就是用空间换时间。



class test
{
private:
	test() {}

public:
	test* gettest()
	{
		static test	t;
		return &t;
	}
}



这是一种饿汉式的方法,当类被创建好了之后,就已经存在一个静态的对象供系统使用,以后不会再改变。但是这也会存在一个问题,当我们使用下面的方法来调用的好时



test t1=test::gettest();就会出现一个类拷贝的问题,这就违背了单例模式的要求,因为编译器会给我们合成一个默认的构造函数,来支持类的拷贝。最后我们没办法,只能将类的拷贝构造函数和赋值运算符的重载声明为私有。于是有了下面这种代码。



class test
{
private:
	test() {}
	test(const test&t);
	test& operator=(const test&t);

public:
	test* gettest()
	{
		static test	t;
		return &t;
	}
}