设计模式学习笔记-----单例模式

  • 为什么使用单例模式

大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。因为Singleton模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。比如使用Socket时,只需要一个Socket对象即可,这时候单例模式就有实战之地了。

  • 实现单例步骤常用步骤

  1. 构造函数私有化
  2. 提供一个全局的静态方法(全局访问点)

  3. 在类中定义一个静态指针,指向本类的变量的静态变量指针

单例模式分类

懒汉式、饿汉式

  • 懒汉式单例模式普通写法  单线程下
Singelton.h
#include <iostream>
using namespace std;

class Singelton
{
private:
	Singelton();
public:
	virtual ~Singelton();
public:
	static Singelton* getInstance();
	void freeInstance();
	static void printT();
private:
	static Singelton *m_Singleton;
	static int m_count;
};

Singelton*	Singelton::m_Singleton = nullptr;
int			Singelton::m_count = 0;

----------------------------------------------------------
Singelton.cpp
#include "Singelton.h"
Singelton::Singelton()
{
	m_Singleton = nullptr;
	m_count = 0;
}

Singelton::~Singelton()
{
}
/**只有当使用的时候才会将对象创建出来**/
Singelton* Singelton::getInstance()
{
	/*单线程下该写法没有问题,多线程有问题*/
	if (m_Singleton == nullptr) 
	{
		m_Singleton = new Singelton();
	}
	return m_Singleton;
}

void Singelton::freeInstance() 
{
	if (m_Singleton != nullptr) 
	{
		delete m_Singleton;
		m_Singleton = nullptr;
		m_count = 0;
	}
}

void Singelton::printT()
{
	cout << "m_count: " << m_count << endl;
}

main.cpp

#include"Singelton.h"
int main()
{
	Singelton* p1 = Singelton::getInstance();
	Singelton* p2 = Singelton::getInstance();
	if (p1 != p2)
	{
		cout << "不是同一个对象" << endl;
	}
	else
	{
		cout << "是同一个对象" << endl;
	}
	p1->printT();
	p2->printT();
	system("pause");
        Singelton::freeInstance();
	return 0;
}
  • 懒汉式单例模式多线程下写法

异同点:单线程的写法使用到多线程后,每次调用GetInstance()静态方法时,必须判断 m_Singleton == nullptr,使程序相对开销增大。在多线程中,该写法会导致多个实例的产生,从而导致运行代码不正确以及内存的泄露。

原因:因为C++中构造函数并不是线程安全的 ,C++中的构造函数简单来说分两步:内存分配 、初始化成员变量。由于多线程的关系,可能当我们在分配内存好了以后,还没来得急初始化成员变量就进行线程切换,另外一个线程拿到所有权后,由于内存已经分配了,但是变量初始化还没进行,因此打印成员变量的相关值会发生不一致现象。

但是当使用懒汉式处理大数据时,此处的锁却变成了影响性能的关键因素。

//多线程优化单例模式
class Singelton
{
private:
	Singelton();
	//防止拷贝构造和赋值操作
	Singelton(const Singelton&) { ; }
	Singelton& operator=(const Singelton &obj) { ; }
public:
	virtual ~Singelton();
public:
	
	static Singelton* getInstance();
	static void freeInstance();
	void printT();
private:
	static Singelton *m_Singleton;
	static std::mutex m_mutex;
	static int m_count;
};

-----------------------------------------------------------
Singelton*	Singelton::m_Singleton = nullptr;
int			Singelton::m_count = 0;
std::mutex  Singelton::m_mutex;
Singelton::Singelton()
{
	
	m_Singleton = nullptr;
	m_count = 0;
}

Singelton::~Singelton()
{
	
}
/**只有当使用的时候才会将对象创建出来**/
Singelton* Singelton::getInstance()
{
	if (m_Singleton == nullptr)  //double check 
	{
		//只有当m_Singleton等于null时,才开始使用加锁机制 二次检查
		m_mutex.try_lock();	
		if (m_Singleton == nullptr)
		{
			m_Singleton = new Singelton();
		}
		m_mutex.unlock();
	}
	return m_Singleton;
}

void Singelton::freeInstance()
{
	if (m_Singleton != nullptr)
	{
		delete m_Singleton;
		m_Singleton = nullptr;
		m_count = 0;
	}
}

void Singelton::printT()
{
	std::cout << "m_count: " << m_count << std::endl;
}

了解了懒汉式单例模式的创建方式后,再来看饿汉式对比度就显而易见了,,饿汉式就是不管有没有人要这个实例对象,都先把实例对象创建出来。

//饿汉式单例模式
class Singelton
{
private:
	Singelton();
	//防止拷贝构造和赋值操作
	Singelton(const Singelton&) { ; }
	Singelton& operator=(const Singelton &obj) { ; }
public:
	virtual ~Singelton();
public:

	static Singelton* getInstance();
	static void freeInstance();
private:
	static Singelton *m_Singleton;
};

Singelton* Singelton::m_Singleton = new Singelton();

Singelton::Singelton()
{
}

Singelton::~Singelton()
{

}
/**只有当使用的时候才会将对象创建出来**/
Singelton* Singelton::getInstance()
{
	return m_Singleton;
}

void Singelton::freeInstance()
{
	if (m_Singleton != nullptr)
	{
		delete m_Singleton;
		m_Singleton = nullptr;
	}
}

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章