C++--设计模式之单例模式

1.单例模式介绍

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。
即:
保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法

结构图:
在这里插入图片描述
为什么要使用单例模式?

在应用系统开发中,我们常常有以下需求:

  • 在多个线程之间,比如初始化一次socket资源;共享同一个资源或者操作同一个对象
  • 在整个程序空间使用全局变量,共享资源
  • 大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。
    因为Singleton模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。

如何构建单例模式

1)构造函数私有化
2)增加静态私有的当前类的指针变量
3)提供静态对外接口,可以让用户获得单例对象,
即提供一个全局的静态方法(全局访问点)

单例模式分为懒汉式和饿汉式

2.懒汉模式

懒汉式:调用的时候才会new一个对象
缺点:这个实现在单线程下是正确的,但在多线程情况下,
如果两个线程同时首次调用GetInstance方法且同时检测到Instance是NULL,
则两个线程会同时构造一个实例给Instance,这样就会发生错误

示例代码说明:

namespace SingleTon_lazy_Test
{

	class SingleTon_lazy
	{
	public:
		//提供静态对外接口,可以让用户获得单例对象
		static SingleTon_lazy* getInstance() {
			//判断会否为第一次调用
			if (instance == NULL) {
				instance = new SingleTon_lazy;
			}
			return instance;
		}

	private:
		//构造函数私有化
		SingleTon_lazy() { 
			std::cout << "new SingleTon_lazy.." << std::endl;
		}


	private:
		//增加静态私有的当前类的指针变量
		static SingleTon_lazy* instance;
		//禁止拷贝和赋值
		SingleTon_lazy(const SingleTon_lazy&) {}; //禁止拷贝
		SingleTon_lazy& operator=(const SingleTon_lazy&) {}; //禁止赋值

	};

	//类外初始化
	SingleTon_lazy* SingleTon_lazy::instance = NULL;
}
int main()
{
	//懒汉模式测试
	SingleTon_lazy_Test::SingleTon_lazy::getInstance();
}

3.饿汉模式

饿汉式: 程序开始运行时,直接new一个对象
特点
饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,
那么饿汉式就是“空间换时间”,因为一开始就创建了实例,
所以每次用到的之后直接返回就好了。饿汉模式是线程安全的.

示例代码说明:

namespace SingleTon_hungry_Test
{
	class SingleTon_hungry
	{
	public:
		static SingleTon_hungry* getInsatnce() {
			return pInstance;
		}
	private:
		SingleTon_hungry() {
			std::cout << " new SingleTon_hungry..." << std::endl;
		}
	private:
		static SingleTon_hungry* pInstance;
		SingleTon_hungry(const SingleTon_hungry&) {}; //禁止拷贝
		SingleTon_hungry& operator=(const SingleTon_hungry&) {}; //禁止赋值
	};

	SingleTon_hungry* SingleTon_hungry::pInstance = new SingleTon_hungry();
}

int main()
{
	//饿模式测试
	SingleTon_hungry_Test::SingleTon_hungry::getInsatnce();
}

4.多线程+单例模式

多线程下的单例模式
懒汉式碰到多线程,是线程不安全,饿汉式是线程安全的
在上述懒汉模式的代码下,假如多个线程都调用了getinstance方法,且都走到了判断为空那一步,可能同时成立。这样会导致多个线程同时创建instance对象,即创建了多次,出现线程不安全的情况。因此,懒汉模式线程是不安全的。

示例代码说明
加锁的经典懒汉实现(线程安全)

//加锁的经典懒汉实现(线程安全)
namespace SingleTon_lazy_MultiThread_Test
{
	std::mutex single_mut;
	class SingleTon_lazy_MultiThread
	{
	public:
		//提供静态对外接口,可以让用户获得单例对象
		//使用double-check来保证线程安全,但是如果处理大量数据时,该锁才成为严重的性能瓶颈
		static SingleTon_lazy_MultiThread* getInstance() {
			//判断会否为第一次调用
			if (instance == NULL) {
				///只有当instance等于null时,才开始使用锁机制 二次检查
				std::unique_lock<std::mutex> munique(single_mut);
				if (instance == NULL) {
					instance = new SingleTon_lazy_MultiThread;
				}				
			}
			return instance;
		}

		static void test()
		{
			single_mut.lock();
			single_mut.unlock();
		}

	private:
		//构造函数私有化
		SingleTon_lazy_MultiThread() {
			std::cout << "new SingleTon_lazy_MultiThread." << std::endl;
		}
	private:
		//增加静态私有的当前类的指针变量
		static SingleTon_lazy_MultiThread* instance;
		SingleTon_lazy_MultiThread(const SingleTon_lazy_MultiThread&) {};//禁止拷贝
		SingleTon_lazy_MultiThread& operator=(const SingleTon_lazy_MultiThread&) {}; //禁止赋值
		



	};
	//类外初始化(静态成员变量不依赖于任何对象,需要在类外单独分配空间)
	SingleTon_lazy_MultiThread* SingleTon_lazy_MultiThread::instance = NULL;

}

int main() {
	//单例不需要考虑释放问题,因为单例只申请了一个对象的内存空间,
	//程序结束时会自动释放掉,不会产生内存泄漏问题;
	SingleTon_lazy_MultiThread_Test::SingleTon_lazy_MultiThread::getInstance();

}

5.单例模式的适用场景

单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等

  • 需要频繁实例化然后销毁的对象。
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  • 有状态的工具类对象。
  • 频繁访问数据库或文件的对象

6.静态成员函数及变量扩展说明

为什么需要要构建静态变量及函数?

需要结合静态成员函数及变量的特性
类的成员函数有如下特性:

-静态成员函数是类的一个特殊的成员函数
-静态成员函数属于整个类所有,没有this指针
-静态成员函数只能直接访问静态成员变量和静态成员函数
-可以通过类名直接访问类的公有静态成员函数
-可以通过对象名访问类的公有静态成员函数
-定义静态成员函数,直接使用static关键字修饰即可

静态成员变量特点:

-静态成员变量属于整个类所有
-静态成员变量的生命期不依赖于任何对象,为程序的生命周期
-可以通过类名直接访问公有静态成员变量
-所有对象共享类的静态成员变量
-可以通过对象名访问公有静态成员变量
-静态成员变量需要在类外单独分配空间
-静态成员变量在程序内部位于全局数据区 (Type className::VarName = value)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值