设计模式 之 单例模式 (C++ 懒汉经典实现 & DCL实现 & 饿汉经典实现)

顾名思义:

单例模式,指的是仅有一个(类)实例。

即:

在应用程序的整个生命周期中,任何时刻,某个类(单例类)仅存在唯一一个实例。

同时仅提供一个全局访问点。


单例的实现一般要求满足:

(1) 类构造函数私有

(2) 提供一个全局访问点 一般是静态的共有方法


一、单例的经典实现

代码如下:

class Singleton
{
public:
	// 全局访问点
	static Singleton *getInstance()
	{
		if (pInstance == NULL)
		{
			pInstance = new Singleton;
		}

		return pInstance;
	}

private:
	static Singleton *pInstance;	// 唯一实例
	Singleton();
};
单例经典实现的缺陷:

在多线程并发的情况下,多个线程同时调用getInstance()方法,可能会出现pInstance = NULL

这时候会同时创建多个线程。


二、单例的多线程下实现("双重锁")

代码如下:

CSingleton.h

#pragma once
#ifndef _CSINGLETON_H_
#define _CSINGLETON_H_
#include <iostream>

struct CCriticalSection
{
public:
	void Lock(){}
	void UnLock(){}
};

// 自己实现的锁
class Lock
{
public:
	CCriticalSection m_cs;
public:
	// 构造函数
	Lock(CCriticalSection cs):m_cs(cs)
	{
		m_cs.Lock();
	}

	// 析构函数
	~Lock()
	{
		m_cs.UnLock();
	}
};

// 单例类(懒汉模式)
class CSingleton
{
private:
	// 下面这些函数要设为private
	CSingleton();	// 防止出现 new CSingleton()这样生成实例的方式

	// 禁止拷贝
	CSingleton(const CSingleton&);
	CSingleton& operator=(const CSingleton&);

	// 析构函数也要设置为private
	~CSingleton();

	// 自动析构类(目的是在程序结束时 自动析构掉单例的实例)
	class CGarbo
	{
	public:
		~CGarbo()
		{
			if (CSingleton::m_pInstance != NULL)
			{
				delete CSingleton::m_pInstance;
				m_pInstance = NULL;
			}
		}
	};
public:
	// 临界区资源(避免多线程的访问冲突)
	//static CCriticalSection m_cs;
	static CSingleton* getInstance();
private:
	// 单例
	static CSingleton* m_pInstance;

	// 自动析构
	static CGarbo m_garbo;
	// 互斥锁
	static CCriticalSection m_cs;
};

#endif
CSingleton.cpp

#include "CSingleton.h"

CSingleton::CSingleton()
{}

CSingleton::~CSingleton()
{}

CSingleton::CSingleton(const CSingleton& instance)
{}

CSingleton& CSingleton::operator=(const CSingleton& instance)
{
	return *this;
}

// 全局访问点 返回单例
CSingleton* CSingleton::getInstance()
{
	if (NULL == m_pInstance)
	{
		Lock lock(m_cs);

		if (NULL == m_pInstance)
		{
			m_pInstance = new CSingleton;
		}
	}

	return m_pInstance;
}

// 懒汉模式

// 静态变量的实例化
CSingleton* CSingleton::m_pInstance = NULL;
CCriticalSection CSingleton::m_cs;
测试代码 main.cpp:

#include <iostream>
#include "CSingleton.h"

using namespace std;

int main(void)
{
	CSingleton *instance1 = CSingleton::getInstance();
	CSingleton *instance2 = CSingleton::getInstance();

	if (instance1 == instance2)
	{
		cout<<"equal instance"<<endl;
	}
	else
	{
		cout<<"different instance"<<endl;
	}

	return 0;
}
【注:上述代码均在VS2012环境下编译运行通过】


大致思想是使用"双重锁"思想。

第二个if 块判断时 先执行加锁操作(关键区实现) 保证只有一个线程可以访问块内的语句。

第一个if 块判断时 因为只有实例不存在时才需要加锁操作 实例存在时 我们只需要直接返回实例即可 提高了效率。


注:上述实现的单例都属于 "懒汉模式"的单例。即:都采取的是用时间换空间的思想。


三、单例的"饿汉模式"

即:无论是否调用该类的实例,在程序开始时就会产生一个该类的实例,并在之后程序中仅返回该单例。

注意:

静态实例初始化保证了线程安全。

REASON:静态实例初始化在程序开始时进入主函数之前就由主线程以单线程方式完成了初始化。

可以不用考虑多线程的问题。

因此这种模式在性能需求较高时,可避免频繁的锁竞争。


代码如下:

class Singleton
{
private:
	static const Singleton* pInstance;
	Singleton(){}
public:
	static const Singleton* getInstace()
	{
		return pInstance;
	}
};

// 外部初始化(进入主函数之前)
const Singleton* Singleton::pInstance = new Singleton;

-------------------------分割线----------------------

接下来需要考虑资源的释放 也就是析构函数。


明天起来再写~~呼呼呼


------------------------03.28 凌晨更新--------------------

增加了析构部分的代码

同时封装为一个单例类

添加了测试代码~


欢迎大家指正~~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值