在实现单例类时,通常要把构造相关的几个函数访问权限设为private或protected(最好是private)。但假设一个大型系统中,有数十个单例类(这很正常,单例类其实是外观模式的一种最常用设计),每一个都这么写显得繁琐不堪。要把这些操作代表的代码复用,可以使用c++语言提供的利器---继承。

设计如下的基类:

 class NonCopyable {
public:
NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
void operator=(const NonCopyable& c) = delete;
};

当单例类继承此类后,客户就无法在复制或赋值此单例类的实例化对象了,这样整个内存只存在一个全局对象。这里的NonCopyable类实现参考了boost::noncopyable。

解决了构造函数访问权限问题后,还有个问题,就是如何实例化?单例类实现的经典做法是在类里声明一个私有的静态类对象的指针,使用get手法返回此对象实例引用,通过此引用再调用类的其它方法。很好,但每个单例类都要这么实现一遍仍然繁琐。此时可以使用C++提供的另一个代码复用的利器--template。先实现一个通用的singleton模板类,模板类型参数传入待实现的单例类名,这样在编译阶段就完成了单例类的构造(模板实例化)。

通用的singleton模板类实现如下:

 template <class T>
class Singleton : public NonCopyable {
private:
static T* inst_; public:
Singleton() {}
virtual ~Singleton() {} static T& inst()
{
if (!inst_) inst_ = new T;
return *inst_;
} static void uninst()
{
if (!inst_) return;
delete inst_;
inst_ = nullptr;
} };
//__declspec(selectany)声明使得我们可以在头文件中初始化一个全局变量
template <class T> __declspec(selectany) T * Singleton<T>::inst_ = nullptr;

自定义单例类实现:

 class singletontest :public Singleton<singletontest>
{
public:
singletontest(){ printf("singletontest constructor function called "); }
~singletontest(){ printf("class test object destroyed "); }
//成员方法
void print(){
printf("singletontest::print function called ");
}
};

测试代码:

 singletontest::inst().print(); //line1
singletontest a; //line 2 无法阻止默认构造,理想中,单例类只允许出现类似line1的调用
printf("singletontest obj a addr is %d\n", &a);
a.print();
singletontest b;
printf("singletontest obj b addr is %d\n", &b);
b.print();
//a(b); //singletontest继承了noncopyable,继承类初始化时先调用父类的构造函数,由于定义成私有,所以构造失败
//a = b; //同上,赋值运算操作符函数同样是私有的

测试结果:

line2行代码写完后编译期并不报错,意味着对象使用默认构造生成。想阻止这种行为,就要把默认构造函数设为私有,但inst()方法里的 new T就会失败,更加得不偿失。

测试 line 8、9代码的错误,编译器可以识别。

代码里存在三层的继承链(singletontest-> singleton<T>-> Noncopyable),但因为类中没有声明虚函数,调用方法上无周转之处,所以性能上没有任何损失。

singletontest:public sington<singletontest>这种写法成文CRTP(Curiously Recurring Template Pattern:奇异递归模板模式),常用于实现静多态,本文不作过多介绍。

最后,一般在多线程环境中讨论单例类创建时,常有饱汉式与饿汉式两种方式,但现代C++已经保证了静态成员变量创建的线程安全性,所以再无讨论这种方式的必要了

当noncopyable遇见singleton的更多相关文章

  1. item2,实现singleton模式

    单例模式? 只能实现一个实例的类成为单例. ============== muduo库中单例模式实现 #include<boost/noncopyable.hpp> //#include ...

  2. pthread_once重塑singleton模式

    单件模式是非线程安全的: // Single threaded version class Foo { private Helper helper = null; public Helper getH ...

  3. boost::singleton

    singleton即单件模式,实现这种模式的类在程序生命周期里只能有且仅有一个实例. 使用singleton,需要包括头文件: #include <boost/serialization/sin ...

  4. Be Better:遇见更好的自己-2016年记

    其实并不能找到好的词语来形容过去的一年,感觉就如此平淡的过了!没有了毕业的稚气,看事情淡了,少了一丝浮躁,多了一分认真.2016也许就是那句话-多读书,多看报,少吃零食多睡觉,而我更愿意说--Be B ...

  5. 23种设计模式--单例模式-Singleton

    一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...

  6. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  7. PHP设计模式(四)单例模式(Singleton For PHP)

    今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...

  8. 自建git node pm2 (不赘述,就说遇见的问题)

    //======================[git]部分 主题部分还是按照网上的办法进行安装. 安装的话  分为两个办法(一个是yum (contos办法)  或者sudo(ubuntu办法) ...

  9. The Java Enum: A Singleton Pattern [reproduced]

    The singleton pattern restricts the instantiation of a class to one object. In Java, to enforce this ...

随机推荐

  1. 61.纯 CSS 创作一只咖啡壶(这个不好看)

    原文地址:https://segmentfault.com/a/1190000015376202 感想: 好像不像呀,啊啊啊.伪元素.定位.动画.width和height包括内边距|边框|内容区. H ...

  2. js day01

    一)什么是JavaScript[以下简称JS] JS是 (1)基于对象 JS本身就有一些现成的对象可供程序员使用,例如:Array,Math,String... JS并不排除你可以自已按一定的规则创建 ...

  3. IDEA使用SpringBoot 、maven创建微服务的简单过程

    使用IDEA新建一个简单的微服务 1. 打开IDEA,File -> New  -> project 打开如下图1-1所示的对话框 图 1-1 2.点击"Next"按钮 ...

  4. [mybatis]Example的用法

    Example类是什么? Example类指定如何构建一个动态的where子句. 表中的每个non-BLOB列可以被包括在where子句中. 例子是展示此类用法的最好方式. Example类可以用来生 ...

  5. 译:SOS_SCHEDULER_YIELD类型等待在虚拟机环境中的增多

    原文出处:Increased SOS_SCHEDULER_YIELD waits on virtual machines 注: 原文的用词是Increased,想译作增强(增长),或者加强,这么译起来 ...

  6. faster-RCNN框架之rpn 较小目标检测,如果只使用rpn,并减少多个候选框

    通常faster-rcnn目标检测有两个步骤,一个是侯选框生成,一个是侯选框微调+目标区分,但是对于单目标识别, 我经常喜欢只使用rpn网络,效果还不错,不过仅仅的rpn使用参考的参数通常会造成一个目 ...

  7. oslo_messaging与rabbitmq

    oslo_messaing通过kombu与rabbitmq建立channel连接,向rabbitmq中发送数据 在oslo_messaging/_drivers/impl_rabbit.py中,初始化 ...

  8. netty(六) websocket开发应用

    package com.lance.net.server.common; import java.net.InetSocketAddress; import org.springframework.s ...

  9. pipeline-安全测试

    代码安全检查 需要安装SonarQube(版本6.7,安装了Findbugs插件) MySQL >=5.6,笔者安装的是MySQL 5.7版本 Jenkins需要安装下列插件: SonarQub ...

  10. [leetcode]23. Merge k Sorted Lists归并k个有序链表

    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. I ...