一.概念

单例模式:其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

  1. class CSingleton
  2. {
  3. //公有的静态方法,来获取该实例
  4. public:
  5. static CSingleton* GetInstance()
  6. {
  7. if ( m_pInstance == NULL )  //判断是否第一次调用
  8. m_pInstance = new CSingleton();
  9. return m_pInstance;
  10. }
  11. //私有构造函数,防止实例化
  12. private:
  13. CSingleton(){};
  14. //私有静态指针变量,指向类的唯一实例
  15. private:
  16. static CSingleton * m_pInstance; //声明一个静态成员
  17. };
  18. CSingleton* CSingleton::m_pInstance = NULL; //定义并初始化静态数据成员
  19. int main()
  20. {
  21. CSingleton* ps1 = CSingleton::GetInstance();
  22. CSingleton* ps2 = CSingleton::GetInstance();
  23. CSingleton* ps3 = ps1->GetInstance();
  24. CSingleton & ps4 = * CSingleton :: GetInstance();
  25. if (ps1 == ps2)
  26. {
  27. cout<< "ps1 = ps2"<<endl;
  28. }
  29. if (ps1 == ps3)
  30. {
  31. cout<< "ps1 = ps3"<<endl;
  32. }
  33. if (&ps4 == ps1)
  34. {
  35. cout<< "ps1 = ps4"<<endl;
  36. }
  37. return 0;
  38. }

单例模式通过类本身来管理其唯一实例,唯一的实例是类的一个普通对象,但设计这个类时,让它只能创建一个实例并提供对此实例的全局访问。

用户访问唯一实例的方法只有
GetInstance() 成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。

有一点要注意:一定要加上
CSingleton* CSingleton::m_pInstance = NULL; 这一句,不然的话编译会出错,因为这一句才是变量定义。

二.单例类CSingleton 有以下特征

它有一个指向唯一实例的静态指针m_pInstance,并且是私有的;

它有一个公有的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例;

它的构造函数是私有的,这样就不能从别处创建该类的实例。

三.存在的问题

1.m_pInstance
指向的空间什么时候释放呢?

如果在类的析构行为中有必须的操作,比如关闭文件,释放外部资源,那么上面的代码无法实现这个要求。我们需要一种方法,正常的删除该实例。

不合理的解决方法:

在程序结束时调用
GetInstance(),并对返回的指针掉用 delete操作。这样做可以实现功能,但不仅很丑陋,而且容易出错。因为这样的附加代码很容易被忘记,而且也很难保证在delete之后,没有代码再调用
GetInstance 函数。也就是说释放操作由使用者来管理,而不是由类本身来管理,这违背了类的单一职责的原则,这是不合理的。

2. 该实例的析构函数什么时候执行?

上面的类里为什么没有析构函数,其实即便你加上析构函数也是可以的,但是这个析构函数不会被执行的。因为你的实例是 new 出来的,所以只有 delete 时,才会调用析构函数,但是在哪里调用 delete 呢!?这又回到了上面的问题。

一种妥善的方法:

  1. class CSingleton
  2. {
  3. public:
  4. static CSingleton* GetInstance()
  5. {
  6. static CSingleton instance; //静态局部变量
  7. return &instance;
  8. }
  9. private:
  10. CSingleton() {}; //构造函数
  11. };

局部静态对象实例 instance 是第一次调用 GetInstance() 时被构造,一直保持活动状态直到应用程序终止,与动态分配对象不同,静态对象当应用程序终止时被自动销毁掉,所以就不必再手动销毁实例了。

当然这里,可以加上析构函数来处理你想要的操作。

这样做的要点有以下几点:

1. 静态变量在内存中只有一份,从而保证了单例模式中单一实例的要求。

2. 静态变量在程序终止时会被自动销毁,从而保证了空间正常释放。

设计模式C++描述----01.单例(Singleton)模式的更多相关文章

  1. JavaScript 设计模式之----单体(单例)模式

    设计模式之--单体(单例)模式 1.介绍 从本章开始,我们会逐步介绍在JavaScript里使用的各种设计模式实现,在这里我不会过多地介绍模式本身的理论,而只会关注实现.OK,正式开始. 在传统开发工 ...

  2. 漫谈设计模式(二):单例(Singleton)模式

    1.前言 实际业务中,大多业务类只需要一个对象就能完成所有工作,另外再创建其他对象就显得浪费内存空间了,例如web开发中的servlet,这时便要用到单例模式,就如其名一样,此模式使某个类只能生成唯一 ...

  3. ① 设计模式的艺术-01.单例(Singleton)模式

    单例模式为何要出现 在工作过程中,发现所有可以使用单例模式的类都有一个共性,那就是这个类没有自己的状态,换句话说,这些类无论你实例化多少个,其实都是一样的. 如果我们不将这个类控制成单例的结构,应用中 ...

  4. Android与设计模式——单例(Singleton)模式

    概念: java中单例模式是一种常见的设计模式.单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类仅仅能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. ...

  5. JAVA中实现单例(Singleton)模式的八种方式

    单例模式 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 基本的实现思路 单 ...

  6. 【Java学习笔记之三十】详解Java单例(Singleton)模式

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  7. 设计一个线程安全的单例(Singleton)模式

    在设计单例模式的时候.尽管非常easy设计出符合单例模式原则的类类型,可是考虑到垃圾回收机制以及线程安全性.须要我们思考的很多其它.有些设计尽管能够勉强满足项目要求,可是在进行多线程设计的时候.不考虑 ...

  8. 单例Singleton模式的两种实现方法

    在设计模式中,有一种叫Singleton模式的,用它可以实现一次只运行一个实例.就是说在程序运行期间,某个类只能有一个实例在运行.这种模式用途比较广泛,会经常用到,下面是Singleton模式的两种实 ...

  9. Java设计模式透析之 —— 单例(Singleton)

    写软件的时候经常需要用到打印日志功能,可以帮助你调试和定位问题,项目上线后还可以帮助你分析数据.但是Java原生带有的System.out.println()方法却很少在真正的项目开发中使用,甚至像f ...

随机推荐

  1. [apue] 使用文件记录锁无法实现父子进程交互执行同步

    父子进程间交互执行是指用一种同步原语,实现父进程和子进程在某一时刻只有一个进程执行,之后由另外一个进程执行,用一段代码举例如下: SYNC_INIT(); , counter=; pid_t pid ...

  2. Hadoop源代码点滴-系统结构(HDFS+YARN)

    Hadoop建立起HDFS和YARN两个字系统,前者是文件系统,管数据存储:后者是计算框架,管数据处理. 如果只有HDFS而没有YARN,那么Hadoop集群可以被用作容错哦的文件服务器,别的就没有什 ...

  3. Disruptor—核心概念及体验

    本文基于最新的3.4.2的版本文档进行翻译,翻译自: https://github.com/LMAX-Exchange/disruptor/wiki/Introduction https://gith ...

  4. SUSE CaaS Platform 4 - 使用 Ceph RBD 作为持久存储 (静态)

    1.所有节点安装 # zypper -n in ceph-common 复制 ceph.conf 到 worker 节点上 # scp admin:/etc/ceph/ceph.conf /etc/c ...

  5. ThinkPHP5 清除runtime缓存文件

    /** * 清除模版缓存 不删除cache目录 */ public function clear_sys_cache() { Cache::clear(); $this->success( '清 ...

  6. Openshift yum安装

    Openshift yum安装: Yum 安装docker [root@DockerServer openshift]# yum repolist [root@DockerServer openshi ...

  7. Java8 Lambda表达式详解手册及实例

    先贩卖一下焦虑,Java8发于2014年3月18日,距离现在已经快6年了,如果你对Java8的新特性还没有应用,甚至还一无所知,那你真得关注公众号"程序新视界",好好系列的学习一下 ...

  8. C# 读取控制台的Console.Write

    一个程序去调用另一个xxx.exe的时候,需要记录下这个exe里面的console.write的输出 public static string InvokeExcute(string Command) ...

  9. php实现商城秒杀

    这一次总结和分享用Redis实现分布式锁来完成电商的秒杀功能.先扯点个人观点,之前我看了一篇博文说博客园的文章大部分都是分享代码,博文里强调说分享思路比分享代码更重要(貌似大概是这个意思,若有误请谅解 ...

  10. 自己写的Weblogic的poc

    """ 暂时只试用于Linux,先试试用一下反弹shell CVE-2017-10271的EXp """ import requests i ...