C++设计模式系列(一)单例模式


一、什么是单例

单例模式是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到的唯一实例;

使用场景

  • 如果系统中只有唯一一个实例存在的类的全局变量的时候才使用单例。
  • 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
  • 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
  • windows的Recycle Bin(回收站)也是典型的单例应用,在整个系统运行过程中,回收站一直维护着仅有的一个实例。
  • 对单例的要求:越简单越小越好,线程安全,内存不泄露

■ 1.1 单例模式分类

单例模式可以分为懒汉式和饿汉式,区别在于创建实例的阶段不同:

懒汉式(线程不安全):程序运行时,当需要使用该实例时,才创建并使用实例。
				  懒汉,从名字上来看就知道,懒么,到了要用到的时候再去;
饿汉式(线程安全):程序启动时就创建实例并初始化,当需要时直接调用即可。
	             饿汉式相对于懒汉式来说,就勤快了,不需要等到需要的时候催着去做,自己在一开始就做好准备了;

■ 1.2 单例类特点

构造函数和析构函数为private类型,禁止外部构造和析构
拷贝构造和赋值构造函数为private类型,目的是禁止外部拷贝和赋值,确保实例的唯一性类中有一个获取实例的静态函数getInstance,可以全局调用

实现思路

在c++中,创建一个对象,首先会先调用类的构造函数,那么,实现单例就是要把构造函数私有化,然后给外界提供一个接口用来返回这个类的实例对象,现在只要让接口每一次返回的都是同一个实例对象就行了,那么这个实例对象就应该被创建为一个静态对象,保存静态数据区。


二、 实现

2.1 基础要点

  • 局只有一个实例:static 特性,同时禁止用户自己声明并定义实例
  • 线程安全
  • 禁止赋值和拷贝
  • 用户通过接口获取实例:使用 static 类成员函数

原因如下:

  • 通过静态的类方法(getInstance) 获取instance,该方法是静态方法,instance由该方法返回(被该方法使用),如果instance非静态,无法被getInstance调用;

  • instance需要在调用getInstance时候被初始化,只有static的成员才能在没有创建对象时进行初始化。并且类的静态成员在类第一次被使用时初始化后就不会再被初始化,保证了单例。

  • static类型的instance存在静态存储区,每次调用时,都指向的同一个对象。

2.2 C++ 实现单例的几种方式

  • 懒汉式
  • 饿汉式
  • 模板类

饿汉式在平时一般不会使用,懒汉式会有进程不安全的因素,在使用中往往会引入智能指针和锁来进行保护,这里只提供懒汉式和饿汉式的基本写法。

2.2.1 懒汉式单例

懒汉式:直到使用时才实例化对象,直到调用getInstance() 方法的时候才 new 一个单例的对象。优点是如果不被调用就不会占用内存。

lazy_single.h

/**
 * @file      lazy single design
 * @datetime  2022-06-03
 * @version   v0.0.1
 */
#include <iostream>
using namespace std;

/**
 * @class     lazy_single
 * @datetime  2022-06-03
 * @version   v0.0.1
 */
class lazy_single
{
public:
    ~lazy_single( )
    {
        cout << "This is < lazy_single > destructor!" << endl;
    }
    
    static lazy_single *getInstance()
    {
        if( !m_pInstance )
        {
            m_pInstance = new lazy_single;   
        }
        return m_pInstance;
    }
private:
    
    lazy_single( )
    {
        cout << "This is < lazy_single > constructor!" << endl;
    }

    lazy_single( lazy_single& ) = delete;
    lazy_single& operator = ( const lazy_single& ) = delete;

    static lazy_single *m_pInstance;
};

lazy_single_test.cpp

/**
 * @file      lazy single design
 * @datetime  2022-06-03
 * @version   v0.0.1
 */

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

using namespace std;
/**
 * [lazy_single_test description]
 * @method    lazy_single_test
 * @author    zc
 * @datetime  2022-06-04
 * @copyright [copyright]
 * @version   v0.0.1
 * @return    [description]
 */
lazy_single *lazy_single::m_pInstance = nullptr;
int lazy_single_test( void )
{
    lazy_single *instance1 = lazy_single::getInstance();
    lazy_single *instance2 = lazy_single::getInstance();

    return 0;
}

2.2.1 饿汉式单例

hungry_single.h

/**
 * @file      hungry single design
 * @datetime  2022-06-03
 * @version   v0.0.1
 */
#include <iostream>
using namespace std;

/**
 * @class     hungry_single
 * @datetime  2022-06-03
 * @version   v0.0.1
 */
class hungry_single
{
public:
~hungry_single( )
{
    cout << "This is < hungry_single > destructor!" << endl;
}

static hungry_single *getInstance( )
{
	return m_pInstance;
}
private:
    hungry_single( )
    {
        cout << "This is < hungry_single > constructor!" << endl;
    }
    hungry_single( hungry_single& ) = delete;
    hungry_single& operator = ( const hungry_single& ) = delete;
    static hungry_single *m_pInstance;
};

hungry_single_test.cpp

/**
 * @file      lazy single design
 * @datetime  2022-06-03
 * @version   v0.0.1
 */

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

using namespace std;
/**
 * [lazy_single_test description]
 * @method    lazy_single_test
 * @author    zc
 * @datetime  2022-06-04
 * @copyright [copyright]
 * @version   [v0.0.1]
 * @return    [description]
 */
hungry_single *hungry_single::m_pInstance = new hungry_single;
int hungry_single_test( void )
{
    hungry_single *instance1 = hungry_single::getInstance();
    hungry_single *instance2 = hungry_single::getInstance();

    return 0;
}

2.2.1 单例类的模板

my_single.h

/**
 * @file      template single design
 * @datetime  2022-06-03
 * @version   v0.0.1
 */
#include <iostream>
using namespace std;

/**
 * @class     template_single
 * @datetime  2022-06-03
 * @version   v0.0.1
 */
#include <iostream>
using namespace std;

template <typename T>
class my_single {
public:
    //外部获取单例的接口
    static T& getInstance( )
    {
        static Token token;
        static T instance(token);   //函数静态变量可以实现延时构造。
        return instance;
    }

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

protected:
    //只有子类才能获取令牌。
    struct Token{};

    //构造和析构函数私有化
    my_single() = default;
    virtual ~my_single() = default;
};

my_single_test.cpp

/**
 * @file      my single design
 * @datetime  2022-06-03
 * @version   v0.0.1
 */

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

using namespace std;
//具体单例模式
//
class Single_1 : public my_single<Single_1> {
public:
    //Token保证,父类需要调用,其他人无法调用。
    Single_1(Token token) 
    {
        cout << "construct: " << this << endl;
        //做你想做的事情。
    }
    ~Single_1() = default;

    //禁止拷贝
    Single_1(const Single_1&) = delete;
    Single_1& operator=(const Single_1&) = delete;
};

class Single_2 : public my_single<Single_2> {
public:
    //Token保证,父类需要调用,其他人无法调用。
    Single_2(Token token) 
    {
        cout << "construct: " << this << endl;
        //做你想做的事情。
    }
    ~Single_2() = default;

    //禁止拷贝
    Single_2(const Single_2&) = delete;
    Single_2& operator=(const Single_2&) = delete;
};

/**
 * [my_single_test description]
 * @method    my_single_test
 * @author    zc
 * @datetime  2022-06-04
 * @version   v0.0.1
 * @return    [description]
 */
int my_single_test( void )
{
    Single_1 &s1 = Single_1::getInstance();
    Single_1 &s2 = Single_1::getInstance();

    Single_2 &s3 = Single_2::getInstance();
    Single_2 &s4 = Single_2::getInstance();
    return 0;
}

参考

C++ 单例模式详解
单例模式(C++实现)
C++单例模式模板 (简单易懂且有效)
C++ 单例模式深度剖析 一
单例模式中的懒汉模式和饿汉模式是什么?区别又是什么?
c++单例模式模板
C++之单例类模板
深入探索单例设计模式:以百度 Apollo 为例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

胖茄子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值