c++设计模式①单例模式 1.懒汉式

1.定义

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。[DP]

2.理解

因为需要只有一个实例对象,最好的控制方式就是类自身来控制,而不是在其他类或者全局变量来控制实例对象的创建。

我对于定义的理解是,为了保证一个类仅有一个实例,所以必须一个访问它的全局访问点。保证一个类仅有一个实例,换言之就是类的构造不对外开放,由其他方式来提供给外部使用,即提供一个访问的全局访问点或者接口。

3.懒汉式(使用时再创建)

这样我们就可以大概获得Singleton类的大概结构:

#pragma once

class Singleton
{
private:  //①构造函数私有化
	Singleton(){};

public:  
	//②提供一个全局访问点,由它来提供给外部Singleton的指针
	//因为要实现在没有Singleton对象的情况下获取到Singleton的指针,所以使用static
	//这样就可以通过类名来获取到对象指针了
	static Singleton* GetInstance();

private: //③ 用来返回的唯一的实例指针
	static Singleton* m_instance;

};
#include "Singleton.h"


//类内的全局变量需要独立初始化
Singleton* Singleton::m_instance = nullptr;

//懒汉式 即 使用再加载
Singleton* Singleton::GetInstance()
{
    if (!m_instance)  //如果m_instance等于nullptr,进入
    {
        m_instance = new Singleton();  //构造函数私有的目的就在于此
    }
    return m_instance;
}

以上的单例模式在单线程是安全的,但是在多线程的时候会出现问题。假设有两个线程同时访问GetInstance函数,且同时走到if (!m_instance) 的时候,会都得到m_instance为nullptr的信息,这样就会各自都会创建对象,这样对象就不在唯一了,与单例模式的定义不符合。主要原因是在创建完成前,大家都可以去创建。

既然会同时访问,那就加锁,

#pragma once
#include <mutex>

class Singleton
{
private:  //①构造函数私有化
	Singleton() {};

public:  
	//②提供一个全局访问点,由它来提供给外部Singleton的指针
	//因为要实现在没有Singleton对象的情况下获取到Singleton的指针,所以使用static
	//这样就可以通过类名来获取到对象指针了
	static Singleton* GetInstance();

private: //③ 用来返回的唯一的实例指针
	static Singleton* m_instance;

	static std::mutex m_mutex;
};

#include "Singleton.h"


//类内的全局变量需要独立初始化
Singleton* Singleton::m_instance = nullptr;
std::mutex Singleton::m_mutex;

//懒汉式 即 使用再加载
Singleton* Singleton::GetInstance()
{
    m_mutex.lock();
    if (!m_instance)  //如果m_instance等于nullptr,进入
    {
        m_instance = new Singleton();  //构造函数私有的目的就在于此
    }
    m_mutex.unlock();
    return m_instance;
}

这样就保证了单例模式的安全,但是现在的代码,每次GetInstance都需要加锁,这样带来的开销很大,会降低效率。所以就有了deouble-check机制的产生。再回顾我们刚刚说的,主要原因是在创建完成前,大家都可以去创建。但如果已经创建好,再有多线程访问,那就不会有这些问题。

所以我们要对后续访问去锁,对创建加锁:

#include "Singleton.h"


//类内的全局变量需要独立初始化
Singleton* Singleton::m_instance = nullptr;
std::mutex Singleton::m_mutex;

//懒汉式 即 使用再加载
Singleton* Singleton::GetInstance()
{
    if (!m_instance)
    {
        m_mutex.lock();
        if (!m_instance)  //如果m_instance等于nullptr,进入
        {
            m_instance = new Singleton();  //构造函数私有的目的就在于此
        }
        m_mutex.unlock();
    }
    return m_instance;
}

这就是double-check模式,这样创建完成后的后续只要走第一个if判断,而且不会进if内加锁灯操作,这样就维护了后续的效率。

如果想要主动销毁到Singleton对象,可以给类添加一个Release函数,来完成对单例对象的主动释放。谨慎,可能会带来野指针的问题,因为可能其他地方还持有着指针,你这时候释放了指针的空间,那么持有者后续进行访问的时候会出现问题。

局部静态变量的方式

#pragma once
#include <mutex>

class Singleton
{
private:  //①构造函数私有化
	Singleton();
	~Singleton();

public:  
	//②提供一个全局访问点,由它来提供给外部Singleton的指针
	//因为要实现在没有Singleton对象的情况下获取到Singleton的指针,所以使用static
	//这样就可以通过类名来获取到对象指针了
	static Singleton* GetInstance();


};

#include "Singleton.h"
#include <iostream>
using namespace std;

Singleton::Singleton()
{
    cout << "Create Singleton." << endl;
}


Singleton::~Singleton()
{
    cout << "Destory Singleton." << endl;
}

//懒汉式 即 使用再加载
Singleton* Singleton::GetInstance()
{
    static Singleton m_instance;
    return &m_instance;
}

这个和饿汉式比较相似,区别是饿汉式是类加载的时候就创建了,这个是调用函数的时候才创建。当然这种方式在c++11是安全的,之前的版本多线程会有错误。

至此,懒汉式单例就结束了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ListenAlone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值