单例模式的C++实现

《C++设计模式》单例模式 介绍了C++的单例模式 阅读详情

   转自:http://blog.youkuaiyun.com/hackbuteer1/article/details/7460019

单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多地方需要这样的功能模块,如系统的日志输出,GUI应用必须是单鼠标,MODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘。

       单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但这样的代码显的很不优雅。 使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对象——也就是说除了一个全局实例外,仍然能创建相同类的本地实例。
《设计模式》一书中给出了一种很不错的实现,定义一个单例类,使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态方法获取该实例。
       单例模式通过类本身来管理其唯一实例,这种特性提供了解决问题的方法。唯一的实例是类的一个普通对象,但设计这个类时,让它只能创建一个实例并提供对此实例的全局访问。唯一实例类Singleton在静态成员函数中隐藏创建实例的操作。习惯上把这个成员函数叫做Instance(),它的返回值是唯一实例的指针。

定义如下:

[cpp]  view plain copy
  1. class CSingleton  
  2. {  
  3. private:  
  4.     CSingleton()   //构造函数是私有的  
  5.     {  
  6.     }  
  7.     static CSingleton *m_pInstance;  
  8. public:  
  9.     static CSingleton * GetInstance()  
  10.     {  
  11.         if(m_pInstance == NULL)  //判断是否第一次调用  
  12.             m_pInstance = new CSingleton();  
  13.         return m_pInstance;  
  14.     }  
  15. };  
用户访问唯一实例的方法只有GetInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。GetInstance()使用 懒惰初始化,也就是说它的返回值是当这个函数首次被访问时被创建的 。这是一种防弹设计——所有GetInstance()之后的调用都返回相同实例的指针:

CSingleton* p1 = CSingleton :: GetInstance();
CSingleton* p2 = p1->GetInstance();
CSingleton & ref = * CSingleton :: GetInstance();
对GetInstance稍加修改,这个设计模板便可以适用于可变多实例情况,如一个类允许最多五个实例。
 
单例类CSingleton有以下特征:
它有一个指向唯一实例的静态指针m_pInstance,并且是私有的;
它有一个公有的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例;
它的构造函数是私有的,这样就不能从别处创建该类的实例。
大多数时候,这样的实现都不会出现问题。有经验的读者可能会问,m_pInstance指向的空间什么时候释放呢?更严重的问题是,该实例的析构函数什么时候执行?
如果在类的析构行为中有必须的操作,比如关闭文件,释放外部资源,那么上面的代码无法实现这个要求。我们需要一种方法,正常的删除该实例。
可以在程序结束时调用GetInstance(),并对返回的指针掉用delete操作。这样做可以实现功能,但不仅很丑陋,而且容易出错。因为这样的附加代码很容易被忘记,而且也很难保证在delete之后,没有代码再调用GetInstance函数。
一个妥善的方法是让这个类自己知道在合适的时候把自己删除,或者说把删除自己的操作挂在操作系统中的某个合适的点上,使其在恰当的时候被自动执行。
我们知道,程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。利用这个特征,我们可以在单例类中定义一个这样的静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例。如下面的代码中的CGarbo类(Garbo意为垃圾工人):
[cpp]  view plain copy
  1. class CSingleton  
  2. {  
  3. private:  
  4.     CSingleton()  
  5.     {  
  6.     }  
  7.     static CSingleton *m_pInstance;  
  8.     class CGarbo   //它的唯一工作就是在析构函数中删除CSingleton的实例  
  9.     {  
  10.     public:  
  11.         ~CGarbo()  
  12.         {  
  13.             if(CSingleton::m_pInstance)  
  14.                 delete CSingleton::m_pInstance;  
  15.         }  
  16.     };  
  17.     static CGarbo Garbo;  //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数  
  18. public:  
  19.     static CSingleton * GetInstance()  
  20.     {  
  21.         if(m_pInstance == NULL)  //判断是否第一次调用  
  22.             m_pInstance = new CSingleton();  
  23.         return m_pInstance;  
  24.     }  
  25. };  
类CGarbo被定义为CSingleton的私有内嵌类,以防该类被在其他地方滥用。
程序运行结束时,系统会调用CSingleton的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。
使用这种方法释放单例对象有以下特征:
在单例类内部定义专有的嵌套类;
在单例类内定义私有的专门用于释放的静态成员;
利用程序在结束时析构全局变量的特性,选择最终的释放时机;
使用单例的代码不需要任何操作,不必关心对象的释放。


进一步的讨论

但是添加一个类的静态对象,总是让人不太满意,所以有人用如下方法来重新实现单例和解决它相应的问题,代码如下:

[cpp]  view plain copy
  1. class CSingleton  
  2. {  
  3. private:  
  4.     CSingleton()   //构造函数是私有的  
  5.     {  
  6.     }  
  7. public:  
  8.     static CSingleton & GetInstance()  
  9.     {  
  10.         static CSingleton instance;   //局部静态变量  
  11.         return instance;  
  12.     }  
  13. };  
使用局部静态变量,非常强大的方法,完全实现了单例的特性,而且代码量更少,也不用担心单例销毁的问题。
但使用此种方法也会出现问题,当如下方法使用单例时问题来了,
Singleton singleton = Singleton :: GetInstance();
这么做就出现了一个类拷贝的问题,这就违背了单例的特性。产生这个问题原因在于:编译器会为类生成一个默认的构造函数,来支持类的拷贝。

最后没有办法,我们要禁止类拷贝和类赋值,禁止程序员用这种方式来使用单例,当时领导的意思是GetInstance()函数返回一个指针而不是返回一个引用,函数的代码改为如下:

[cpp]  view plain copy
  1. class CSingleton  
  2. {  
  3. private:  
  4.     CSingleton()   //构造函数是私有的  
  5.     {  
  6.     }  
  7. public:  
  8.     static CSingleton * GetInstance()  
  9.     {  
  10.         static CSingleton instance;   //局部静态变量  
  11.         return &instance;  
  12.     }  
  13. };  

但我总觉的不好,为什么不让编译器不这么干呢。这时我才想起可以显示的声明类拷贝的构造函数,和重载 = 操作符,新的单例类如下:

[cpp]  view plain copy
  1. class CSingleton  
  2. {  
  3. private:  
  4.     CSingleton()   //构造函数是私有的  
  5.     {  
  6.     }  
  7.     CSingleton(const CSingleton &);  
  8.     CSingleton & operator = (const CSingleton &);  
  9. public:  
  10.     static CSingleton & GetInstance()  
  11.     {  
  12.         static CSingleton instance;   //局部静态变量  
  13.         return instance;  
  14.     }  
  15. };  
关于Singleton(const Singleton);和 Singleton & operate = (const Singleton&);函数,需要声明成私有的,并且只声明不实现。这样,如果用上面的方式来使用单例时,不管是在友元类中还是其他的,编译器都是报错。
不知道这样的单例类是否还会有问题,但在程序中这样子使用已经基本没有问题了。


考虑到线程安全、异常安全,可以做以下扩展
[cpp]  view plain copy
  1. class Lock  
  2. {  
  3. private:         
  4.     CCriticalSection m_cs;  
  5. public:  
  6.     Lock(CCriticalSection  cs) : m_cs(cs)  
  7.     {  
  8.         m_cs.Lock();  
  9.     }  
  10.     ~Lock()  
  11.     {  
  12.         m_cs.Unlock();  
  13.     }  
  14. };  
  15.   
  16. class Singleton  
  17. {  
  18. private:  
  19.     Singleton();  
  20.     Singleton(const Singleton &);  
  21.     Singleton& operator = (const Singleton &);  
  22.   
  23. public:  
  24.     static Singleton *Instantialize();  
  25.     static Singleton *pInstance;  
  26.     static CCriticalSection cs;  
  27. };  
  28.   
  29. Singleton* Singleton::pInstance = 0;  
  30.   
  31. Singleton* Singleton::Instantialize()  
  32. {  
  33.     if(pInstance == NULL)  
  34.     {   //double check  
  35.         Lock lock(cs);           //用lock实现线程安全,用资源管理类,实现异常安全  
  36.         //使用资源管理类,在抛出异常的时候,资源管理类对象会被析构,析构总是发生的无论是因为异常抛出还是语句块结束。  
  37.         if(pInstance == NULL)  
  38.         {  
  39.             pInstance = new Singleton();  
  40.         }  
  41.     }  
  42.     return pInstance;  
  43. }  

之所以在Instantialize函数里面对pInstance 是否为空做了两次判断,因为该方法调用一次就产生了对象,pInstance == NULL 大部分情况下都为false,如果按照原来的方法,每次获取实例都需要加锁,效率太低。而改进的方法只需要在第一次 调用的时候加锁,可大大提高效率。
C++11实现单例模式 1 线程不安全的单例模式 类的静态成员变量由所有对象共享,也就是在内存中只有一份,我们可以利用这个特性凭直觉写出如下的单例模式class Singleton { public: static Singleton* getInstance(); Singleton(const Singleton& rhs) = delete; Singleton& operator=(con... 阅读详情

相关推荐

C++的三种单例模式-----深度解析

简介 因为在设计或开发中,肯定会有这么一种情况,一个类只能有一个对象被创建,如果有多个对象的话,可能会导致状态的混乱和不一致。这种情况下,单例模式是最恰当的解决办法。它有很多种实现方式,各自的特性不相同,使用的情形也不相同。今天要实现的是常用的三种,分别是饿汉式、懒汉式和多线程式。 通过单例模式, 可以做到: 确保一个类只有一个实例被建立 提供了一个对对象的全局访问指针 在不影响单例类的客户端的情况下允许将来有多个实例 懒汉式 懒汉式的特点是延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉么,很

qq_33287871的博客 2525

【C++】C++ 单例模式总结(5种单例实现方法)

C++ 单例模式的几种实现方式。

unonoi的博客 12万+

C++ 设计模式3:单例模式

单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例;具体运用场景如:设备管理器,系统中可能有多个设备,但是只有一个设备管理器,用于管理设备驱动;数据池,用来缓存数据的数据结构,需要在一处写,多处读取或者多处写,多处读取;

琅嬛福地 2732

C++ 单例模式

C++ 单例模式 Arkin Mechanic . Keep coding. ​关注他 27 人赞同了该文章 1. 什么是单例模式 单例模式(Singleton Pattern,也称为单件模式),使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。 定义一个单例类: 私有化它的构造函数,以防止外界创建单例类的对象; ...

jfkidear的专栏 1159

c++实现单例模式完整源代码

c++实现单例模式完整源代码Singleton.hppmain.cpp Singleton.hpp #ifndef __SINGLETON_H__ #define __SINGLETON_H__ #include <iostream> #include <string.h> #include <mutex> using namespace std; class Singleton_Lazy { public: static Singleton_Lazy* getIn

希望我的博客,能帮上你解决学习中工作中所遇到的问题 601

STM32驱动WS2812B实现音乐频谱可视化系统

本文详细介绍了基于STM32驱动WS2812B灯带实现音乐频谱可视化系统的设计与实现。通过FFT算法实时分析音频信号,将频谱映射到炫彩灯光控制系统,结合PWM和DMA技术实现低延迟响应。系统支持多模式切换和动态亮度调节,适用于创意灯光秀和智能家居场景。

weixin_29171129的博客 302

cpp单例模式的实现

单例模式的意义 保证全局只会创建一个对象,比如 日志模块全局只有一个,windows的任务管理器等,这样可以避免频繁的创建销毁对象,还可以避免对共享资源的多重占用,具体例子和好处坏处看参考资料[9],不赘述 几种考虑 几个要考虑的问题:懒加载;;线程安全生存周期的考虑;;反序列化;;反射单例;;克隆单例 首先是一个唯一性,保证全部成员只能访问到一个共同的对象 为了防止对象被创建多次,要把构造函数设为private,以防止被他人调用重复建立,而自己单独实现一个接口用来获取实例(可以把构造函数当作这个

ptgood的博客 1865

那些年-SAP固定资产导入AS91 OASV

固定资产起初导入步骤: 第一部分:资产数据导入 1)两个日期配置 填写图片摘要(选填) Specify transfer date/last closed fiscal year 这里的日期填写系统切换日期,如果系统是2015-10-01上线,这里填写2015-09-3 填写图片摘要(选填) Specifylast period posted in prv system 这里指定系统切换的上一期间。这里写2015-09 填写图片摘要(选填) ​2)AS91新增 填写固定资产的分类,公司

阿土工作室 7947

C++ 实现单例模式

C++实现单例模式单例模式的基本概念基本实现完整实现 单例模式的基本概念 基本实现 #include<cstdio> class singleton { public: static singleton* get_singleton(){ if(instance_ == nullptr){ instance_ = new single...

zlgahu的博客 5594

光致发光(Photoluminescence, PL)入门版

关于光致发光的实际应用做出一些解释。

sinat_40546227的博客 1万+

一、Abaqus CAE 入门操作(薄膜应力计算)

一、Abaqus CAE 入门操作(薄膜应力计算)

A20802013的博客 4370

C++单例模式实现

单例模式 单例模式:要求类只有一个对象实例,数据库连接池、线程池以及Windows任务管理器都是单例模式的应用。 那么如何去实现一个单例模式呢?C++中有5种实现的方式,首先从最简单说起 1. 单线程实现 常规写法 class Singleton{ public: static Singleton* getInstance() { if(_instance == nullptr) ...

一个不知名码农的专栏 3492

OPENSSL使用方法

预备知识KEY 通常指私钥。CSR 是 Certificate Signing Request 的缩写,即证书签名请求,这不是证书,只是包含申请证书的基本信息。生成证书时要把这个提交给权威的证书颁发机构,颁发机构审核通过之后,再根据这些申请信息生成相应的证书。CRT 即 certificate的缩写,即证书。 X.509 是一种证书格式。对X.509证书来说,认证者总是CA或由CA指定的人,一份...

zxm8513优快云博客 1212

C++实现单例模式

C++单例模式

u012732168的博客 1万+

2023年全国职业院校技能大赛 网络系统管理服务模块 Linux部分讲解

网络系统管理,Linux,服务部署,Chinaskills,2023国赛

weixin_62926639的博客 1548

Lammps实现Ar的沸腾过程(包含in文件)

Lammps实现简单的沸腾过程

Rockyoung 3503

C++单例模式的几种实现

本文介绍C++单例模式的集中实现方式,以及利弊 局部静态变量方式 //通过静态成员变量实现单例 //懒汉式 class Single2 { private: Single2() { } Single2(const Single2 &) = delete; Single2 &operator=(const Single2 &) = delete; public: static Single2 &GetInst() {

恋恋风辰的技术博客 6358

破晓之光:GTK#框架让C# WinForm程序跨平台运行的终极指南

GTK#框架的出现,彻底打破了C# WinForm只能在Windows上运行的桎梏。

墨夶的博客 605

设计模式实现CPP——单例模式

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。常用于共享资源(如配置信息、线程池、数据库连接等),保证全局一致性。

qq_45835091的博客 485

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

单例模式C++实现

前一段时间看自学了设计模式,发现好多书的java实现的。因为本人是从事C++开发的,因此想尝试用C++自己实现一遍,加深理解。不足之处还望大神们赐教。 单例模式 定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 适用性:当类只能有一个实例。这种情况应该很常见,所以单例模式也是个人觉得最常用的简单设计模式之一了。 优点: 1、  对唯一实例的受控访问 2、  缩小

hai200501019的专栏 875

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++单例模式的实现

很多场景下都可以用到单例模式作为设计模式,比如:线程池类,服务器类(待实现挖坑),内存池类(待实现挖坑),单例模式的两种实现方式:饿汉模式和懒汉模式饿汉模式的缺点如下:1. 由于编译时需要初始化静态变量,导致程序启动变慢2. 如果有两个单例模式设计的类,而且其中一个依赖另一个,但是编译器并不确定哪个类的先初始化,此时有可能导致编译错误。

weixin_46366676的博客 1268

设计模式之单例模式(Singleton Pattern)C++实现

单例模式(Singleton Pattern):这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。 主要解决:解决一个全局使用的类,频繁地创建和销毁 缺点:没有接口,不能继承 使用场景:产生唯一序列号、web中的计数器、消耗资源多的(I/O、数据库连接) 注意:

奔跑的小河 562

C++单例模式的六种实现

(如有错误,请联系我更正,以免误导他人!)        C++中单例模式的应用非常广泛,在我们平时使用的windows操作系统中就存在大量的单例应用。如:回收站、任务管理器、文件资源管理器等。        单例模式的实现也有许许多多的方法,每种实现方法都有各自的优点和实用场景。 实现一: class Singleton { public: static Singleton* get

break;的博客 1827

用c++来实现单例模式

单例模式是使用广泛的一种设计模式,又称为单件模式、单子模式。其意图是保证一个类仅有一个实列,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多的地方都需要这样的功能模块,如系统的日志输出,操作系统只能有一个窗口管理器,一台pc连一个键盘等等。 单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但这样的代码显的很不优雅。 使用全局对象能够保证方便地访问实例,但...

jellocomeon的专栏 397
上一篇: string类的实现
day__day__up
博客等级 码龄11年 15粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值