C++中的单例模式

单例模式
    1、只能创建出一个对象的类,这种类就叫作单例类,这种模式就叫作单例模式。
    2、为什么需要单例模式,是为了提高安全性和稳定性的技巧。
        只允许存在唯一对象实例
        单例模式的商业应用:
            网站计数器
            日志管理系统
            连接池、线程池、内存池
    3、获取对象实例的专门方法
        a、全局变量的定义不受控制,能防君子不能防小人
        b、专门方法是类的一部分,"我是类型我做主",
        借助类禁止在外部创建对象,仅在类内部提供获取对象的接口。
    4、如何实现单例模式
        a、禁止在类外部创建实例,私有所有的构造函数 private
        b、类自己维护其唯一实例,
            静态成员变量 static 类名 instance;
            静态成员指针 static 类名* instance;
        c、提供访问该实例的方法,静态成员函数getInstance() 

    5、饿汉单例模式
        不管是否需要对象都已经创建好了。
        优点:效率高、速度快、稳定。
        缺点:浪费资源,不管需不需要对象都已经创建好;

    6、懒汉单例模式
        当首次使用获取对象时才会真正创建出对象。
        优点:节约资源
        缺点:效率低,速度慢,不安全(多线程情况下)。
    下面我们按照第四点来实现一个单例模式:

#include<iostream>
using namespace std;
class Student
{
private:
	//static Student instance;	
	Student(){}
	Student(const Student & that)
	{
		cout<<"I'm copy"<<endl;
	}
	Student& operator =(const Student& that)
	{
		cout<<"我是赋值构造函数!"<<endl;
	}
public:
	static Student& getobj(void)
	{

		static Student obj;

		return obj;
	}
};

int main()
{
	Student& stu1=Student::getobj();
	cout<<&stu1<<endl;
	Student& stu2=Student::getobj();
	cout<<&stu2<<endl;
}

这个例子:我们分别用stu1和stu2得到两个对象,按照理解判断应该是两个对象,但把对象的地址打印出来我们发现,是同一个地址,这就说明,这是同一个对象,所以这个类只能创建一个对象,所以是单例模式。

饿汉模式的单例:

#include<iostream>
using namespace std;
class Student
{
private:
	static Student obj;	
	Student(){}
	Student(const Student & that)
	{
		cout<<"I'm copy"<<endl;
	}
	Student& operator =(const Student& that)
	{
		cout<<"我是赋值构造函数!"<<endl;
	}
public:
	static Student& getobj(void)
	{
		return obj;
	}
};
Student Student::obj;
int main()
{
	Student& stu1=Student::getobj();
	cout<<&stu1<<endl;
	Student& stu2=Student::getobj();
	cout<<&stu2<<endl;
}

注意:我们在类中用static声明了一给成员,那么这个成员只能在类外定义也就是Student Student::obj;这里的obj是先创建了,无论是不是用,所以称为饿汉模式。

再来看一下懒汉模式:

#include<iostream>
using namespace std;
class Student
{
private:
	static Student* obj;	
	Student(){}
	Student(const Student & that)
	{
		cout<<"I'm copy"<<endl;
	}
	Student& operator =(const Student& that)
	{
		cout<<"我是赋值构造函数!"<<endl;
	}
public:
	static Student& getobj(void)
	{
		if(Student::obj==NULL)
		{
			obj=new Student;
			return *obj;
		}
	}
};
Student* Student::obj;
int main()
{
	Student& stu1=Student::getobj();
	cout<<&stu1<<endl;
	Student& stu2=Student::getobj();
	cout<<&stu2<<endl;
}

这个是懒汉模式,运行结果也是同样的对象地址,注意,我没有写析构函数释放资源,稍微有点不合理,大家可以自己试着加一下,new最好要配合delete使用。

考虑到线程安全,做出扩展


class Lock

{

private:       

	CCriticalSection m_cs;

public:

	Lock(CCriticalSection  cs) : m_cs(cs)

	{

		m_cs.Lock();

	}

	~Lock()

	{

		m_cs.Unlock();

	}

};

 

class Singleton

{

private:

	Singleton();

	Singleton(const Singleton &);

	Singleton& operator = (const Singleton &);

 

public:

	static Singleton *Instantialize();

	static Singleton *pInstance;

	static CCriticalSection cs;

};

 

Singleton* Singleton::pInstance = 0;

 

Singleton* Singleton::Instantialize()

{

	if(pInstance == NULL)

	{   //double check

		Lock lock(cs);           //用lock实现线程安全,用资源管理类,实现异常安全

		//使用资源管理类,在抛出异常的时候,资源管理类对象会被析构,析构总是发生的无论是因为异常抛出还是语句块结束。

		if(pInstance == NULL)

		{

			pInstance = new Singleton();

		}

	}

	return pInstance;

}

猜你喜欢

转载自blog.csdn.net/Dachao0707/article/details/81514463
今日推荐