前言:

本文将探讨单例类设计模式,单例类的懒汉模式/饿汉模式,单例类的多线程安全性,最后将利用C++模板减少单例类代码量。

本文假设有一个Manager管理类,并以此为探究单例类的设计模式。


懒汉模式

懒汉模式:顾名思义,是一种典型的拖延(lazy)策略。当第一次要用单例类的时候,再产生实例。

类声明:

class Manager{
public:
~Manager();
//提供单例对象访问
static Manager* getInstance();
//删除单例对象
static void deleteInstance();
void dosomething();protected:
//构造函数声明为 保护方法
Manager();
//单例对象指针
static Manager* s_Manager;
};

//单例对象指针初始化为nullptr,防止指向了未定义的数据
Manager* Manager::s_Manager = nullptr;//提供单例类对象访问
Manager* Manager::getInstance(){
   //当没有存在实例时(一般是指准备第一次用)时,才生成新实例
   if(!s_Manager)s_Manager = new CacheManger();
   return s_Manager;
}//删除单例类
void Manager::deleteInstance(){
   if(s_Manager){deleted s_Manager;s_Manager = nullptr;//别忘了赋予空指针,否则指向未定义数据
   }
}void Manager::dosomething(){
   //dosometing
}

这样我们就能在平时的程序用

Manager::getInstance()->dosomething();

来运用单例类来做某些操作了。

懒汉模式with线程安全

但是上面的例子,并不能保证线程安全。

假如没有实例时,然后某两个线程都几乎同时使用getInstance(),那么很可能会产生2份实例,其中一份还会变成泄露的内存。

为了解决线程安全问题,自然想到用锁:(本文使用了C++11 <mutex>的std::mutex作为互斥锁,在类额外增加了一个静态变量std::mutext s_mtx;)

//提供单例类对象访问
Manager* Manager::getInstance() {if (!s_Manager) {//上锁std::lock_guard<std::mutex> lock(s_mtx);//当没有存在实例时(一般是指准备第一次用)时,才生成新实例if (!s_Manager){s_Manager = new Manager();}//解锁
    }return s_Manager;
}//删除单例类
void Manager::deleteInstance() {if (s_Manager) {//上锁std::lock_guard<std::mutex> lock(s_mtx);if (s_Manager) {delete s_Manager;//别忘了赋予空指针,否则指向未定义的数据s_Manager = nullptr;}//解锁
    }
}

为什么不是(上锁,检查,操作,解锁)或者(检查,上锁,操作,解锁),而是使用了双重检查(检查,上锁,检查,操作,解锁)?

  1. 上锁的成本远远比检查空指针要高,且当需要产生实例时才需要锁操作。而实际上大量多次使用getInstance时(因为已经产生了实例)并不需要上锁,若先上锁,则会严重造成性能阻塞。
  2. 仅仅是检查后再上锁,则根本没有做到任何线程安全。

饿汉模式

饿汉模式与懒汉模式相反,是程序一开始就生成唯一实例。这样就不用检查是否存在实例,而且也无需考虑产生实例时的线程安全。

class Manager {
public:~Manager();//提供单例对象访问static Manager& getInstance();void dosomething();
protected://构造函数声明为 保护方法
    Manager();//单例对象指针static Manager s_Manager;
};//提供单例类对象访问
Manager& Manager::getInstance(){return s_Manager;
}

使用方法:

Manager::getInstance().dosomething();

可以看到代码比懒汉模式简单多了。

在大量使用检查空指针造成的性能瓶颈而内存始终充足时,可以考虑使用饿汉模式

Meyers Singleton(目前最推荐的C++单例写法)

class Singleton {
public:static Singleton& Instance() {static Singleton theSingleton;return theSingleton;}
private:Singleton();Singleton(Singleton const&);Singleton& operator=(Singleton const&); ~Singleton();
};

这段代码很简单,虽然看上去和懒汉模式类似,只是static变量的位置从类移动到了实例获取函数内。

但是实际上由于C++的机制,当第一次调用该函数时,实例才会被构建出来。

这样既可以得到饿汉模式的线程安全,又可以有懒汉模式的按需分配的功能。

应用场景注意

单例类设计模式算是比较经典的一个模式,但是需要注意,它并不是想象中那么美好。

  1. 它是一种换皮的全局变量。
  2. 它促进了耦合。
  3. 它可能对并发不友好(取决于你使用的单例写法)。

一些替代方案:

  1. 当你仅需要全局可见的方法时,应该用类静态方法而不是一个类实例。
  2. 尽可能为实例提供其它便捷的访问方式(传参/基类获取/服务定位器获取等),而不是通过提供全局可见的访问方式。
  3. 如果你只是需要类保证只有唯一对象而不需要全局性,那么应对外封闭获取实例接口(其实就是不可全局获取实例的)。

所以要注意单例类设计模式不应被泛用,通过上面的替代方案多多少少也就减少了很多不必要的单例设计。


游戏设计模式系列-其他文章:

https://www.cnblogs.com/KillerAery/category/1307176.html

转载于:https://www.cnblogs.com/KillerAery/p/9097529.html

游戏设计模式——C++单例类相关推荐

  1. java 构造函数 单例_Java中的私有构造函数和单例类 - Break易站

    Java 构造函数 Java中的私有构造函数和单例类 我们首先分析下面的问题: 我们可以有私人构造函数吗? 正如你可以很容易猜到的,就像我们可以为构造函数提供访问说明符一样.如果它是私人的,那么它只能 ...

  2. java中单例设计模式登记式单例类_java23种设计模式-创建型模式之单例模式

    单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频 ...

  3. 设计模式详解:Singleton(单例类)

    Singleton(单例类) 设计模式学习:概述 意图 保证每一个类仅有一个实例,并为它提供一个全局访问点. 顾名思义,单例类Singleton保证了程序中同一时刻最多存在该类的一个对象. 有些时候, ...

  4. 单例类(单例设计模式)[java]

    设计模式:解决某一类问题的方案(模式) 单例类:只允许创建一个对象实例的类,称为单例类 单例模式:让一个类在一个程序中只能创建一个对象 eg:任务管理器(无论你点击多少次,都只能创建一个窗口) 实现流 ...

  5. 第六十二课、单例类模板

    一.单例模式(一个类只有一个对象,且单例模式一般不用释放) 1.要控制类的对象数目,必须对外隐藏构造函数 (1).将构造函数的访问属性设置为private (2).定义instance并初始化为NUL ...

  6. 详略。。设计模式1——单例。。。。studying

    设计模式1--单例 解决:保证了一个类在内存中仅仅能有一个对象. 怎么做才干保证这个对象是唯一的呢? 思路: 1.假设其它程序可以任意用new创建该类对象,那么就无法控制个数.因此,不让其它程序用ne ...

  7. java软件设计模式只单例设计模式

    概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计 ...

  8. 菜鸟之路-浅谈设计模式之单例设计模式

    单例设计模式 定义:确保一个类仅仅有一个实例,并且自行实例化并向整个系统提供这个实例. 单例模式是一种经常使用的软件设计模式.在它的核心结构中仅仅包括一个被称为单例的特殊类. 通过单例模式能够保证系统 ...

  9. (七)boost库之单例类

    一.boost.serialzation的单件实现 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问 ...

最新文章

  1. OWASP TOP10(2017)
  2. Ext.Net中常用的验证
  3. OceanBase数据库开发和运维漫谈
  4. win7怎么清除卸载Ghost启动项的残留
  5. jQuery窗口调整大小
  6. 【深度学习】基于Keras的手写体识别
  7. 30 个最好的数据可视化工具推荐
  8. python爬虫必看书籍推荐
  9. XTUOJ-1281-Cute String
  10. pdf文档动态插入水印,45度角,位于文档中央,可插入中文
  11. 五脏六腑在脸上的反射区图片_痘痘脸部反射区图痘痘的位置反射五脏六腑的病症 [哈哈镜]...
  12. python aks_使用环回aks和terraform构建基于打字稿的游戏后端
  13. 清华大学计算机系张昕,程序设计语言的研究与发展——如何推进国内程序设计语言的教育和研究?丨CNCC技术论坛...
  14. xmind 8 pro安装jh
  15. Win10台式电脑网线正常但连不上网。
  16. Kaggle教程 机器学习中级4 Pipeline
  17. 圆拟合Taubin fit 方法
  18. IDEA 安装插件后打不开
  19. Centos7 安装DB2
  20. 于 HTML5 WebGL 的民航客机飞行监控系统

热门文章

  1. [Python]再学 socket 之非阻塞 Server
  2. animateWithDuration:animations:completion:
  3. Java XML解析工具 JDOM介绍及使用实例
  4. select * from mys where id=2;
  5. Javascript 面向对象全新理练之数据的封装
  6. Linux下载交通图片数据集CityScapes Dataset
  7. 数据结构源码笔记(C语言):Josephus问题之循环链接表
  8. 封装函数 f,使 f 的 this 指向指定的对象
  9. 数据预处理——数据清洗、异常值与重复数据的检测
  10. 用python实现自动填数生成表格v2.0