c++单例模式

Posted 技术热爱者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++单例模式相关的知识,希望对你有一定的参考价值。

单例模式:

单例大约有两种实现方法:懒汉与饿汉。
懒汉:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化,
饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。
(1)饿汉

饿汉单例,即在最开始的时候,静态对象就已经创建完成;
设计方法是类中包含一个静态成员指针,该指针指向该类的一个对象,提供一个公有的静态成员方法,返回该对象指针;为了使得对象唯一,还需要将构造函数设为私有,代码如下:

class Sigletion
{
	//构造函数为私有;
 
	Sigletion()
	{
		cout << "Sigletion()" <<endl;
	}
 
	static Sigletion * intance; //静态成员,指向Sigletion对象的指针。
 
public:
	//提供静态共有方法,可以使用类名加域名进行访问,返回对象指针;
	static Sigletion* GetSigletion()
	{
		return intance;
	}
};
 
Sigletion* Sigletion:: intance = new Sigletion;

测试代码:

int main()
{
	/*我们注意到,在刚进入main函数,我们就打印了一句“”main begin“”,为什么要在这里加入一句输出语句呢?
	因为我们此时的单例模式采用的是饿汉单例,所以,哪怕你还没用到我这个对象,我也会先创建一个出来,
	先占着,即所谓的饿汉,其实就是类似于全局变量的构造是在进入main函数之前的原理,*/
 
	cout << "main begin" <<endl; //验证静态对象的创建在main之前。
 
	//验证无法创建实例。
	//Sigletion tmp;
	//Sigletion *ptr = new Sigletion;
 
	//调用共有的静态成员方法
	Sigletion *ptr = Sigletion::GetSigletion();
	Sigletion *ptr2 = Sigletion::GetSigletion();
	if (ptr == ptr2)
	{
		cout << "yes" <<endl;
	}
	else
	{
		cout << "no"<<endl;
	}
 
	cout << "hello..." <<endl;
	system("pause");
	return 0;
}

单例的饿汉实现是线程安全的,因为对象在使用前就已经创建出来了

(2)懒汉:

所谓懒汉模式,就是尽可能晚的创建这个对象的实例,即在单例类第一次被引用时将自己初始化;其实C++里很多地方都是类似这样的思想,比如晚绑定,写时拷贝技术等,就是尽量使资源的利用最大化,不要让空闲的人还占着有限的资源。

class Sigletion2
{
	Sigletion2()
	{
		cout << "Sigletion2()" <<endl;
	}
 
	static Sigletion2* intance2;
 
public:
 
	static Sigletion2* GetSigletion2()
	{
		if (intance2 == NULL)
		{
			intance2 = new Sigletion2();
			cout << "it is once" <<endl;
		}
		else
		{
			cout << "it is not once" <<endl;
		}
		return intance2;
 
	}
 
};
 
Sigletion2* Sigletion2:: intance2 = NULL;  //先初始化为空,等真正用上这个单例的时候再创建这个例。

(3)懒汉的线程安全问题:

如果此时多线程进行操作,简单点以两个线程为例,假设pthread_1刚判断完 intance 为NULL 为真,准备创建实例的时候,切换到了pthread_2, 此时pthread_2也判断intance为NULL为真,创建了一个实例,再切回pthread_1的时候继续创建一个实例返回,那么此时就不再满足单例模式的要求了, 既然这样,是因为多线程访问出的问题,那我们就来加把锁,使得线程同步;

class singleton
{
private:
	singleton()
	{
		pthread_mutex_init(&mutex);
	}
 
	static singleton* p;
	static pthread_mutex_t mutex;
public:
	static singleton* initance()
	{
		pthread_mutex_lock(&mutex);
		if (p == NULL)
		{
			p = new singleton();
		}
		pthread_mutex_unlock(&mutex);
 
		return p;
	}
};
 
pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;

那么我们这样写的代码是没有问题的,但是效率可能有点低,因为加锁是一个非常耗时的操作,没有必要每次都要加锁解锁,只有刚开始创建对象的时候需要加锁。如果对象都
创建出来了,就没必要加锁解锁了,直接返回这个对象的指针。

class singleton
{
private:
	singleton()
	{
		pthread_mutex_init(&mutex);
	}
 
	static singleton* p;
	static pthread_mutex_t mutex;
public:
	static singleton* initance()
	{
		if (p == NULL)   //p != NULL,说明对象已经创建出来了,直接返回对象的指针,没必要在加锁解锁浪费时间。
		{
			pthread_mutex_lock(&mutex);
			if (p == NULL)
			{
				p = new singleton();
			}
			pthread_mutex_unlock(&mutex);
		}
		return p;
	}
};
 
pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;

允许可变数目的实例,基于单例模式我们可以扩展,使用与单例控制相似的方法来获得指定个数的对象实例。(即单例类内有多个静态对象指针成员,每次当单例类被引用时随机分配一个实例对象);

单例模式的适用场景
(1)系统只需要一个实例对象,或者考虑到资源消耗的太大而只允许创建一个对象。
(2)客户调用类的单个实例只允许使用一个公共访问点,除了该访问点之外不允许通过其它方式访问该实例 (就是共有的静态方法)。

以上是关于c++单例模式的主要内容,如果未能解决你的问题,请参考以下文章

C++设计模式:单例模式

C++ 安全单例模式总结

设计模式--单例模式C++实现

C++特殊类设计(单例模式)

C++ 单例模式(singleton)

C++ 单例模式(singleton)