C++ 设计模式 单件模式
2021/5/17 20:55:58
本文主要是介绍C++ 设计模式 单件模式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
以下内容均来自GeekBand极客班C++ 设计模式课程(李建忠老师主讲)
Singleton
面向对象很好地解决了"抽象"的问题,但是必不可免地付出一定的代价,对于通常情况来讲,面向对象的成本大都可以忽略不计。但是某些情况,面向对象所带来的成本必须谨慎处理。
“对象性能”模式
典型模式:
Singleton
Flyweight
动机(Motivation)
在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中存在一个实例,才能确保它们的逻辑正确性,以及良好的效率。
如果绕过常规的构造器,提供一个机制来保证一个类只有一个实例?
这应该是类设计者的责任,而不是使用者的责任。
示例
//singleton class Singleton{ private: //构造和拷贝构造都是私有类型 Singleton(); Singleton(const Singleton & other); public: static Singleton * getInstance(); static Singleton * m_instance; }; Singleton * Singleton::m_instance = nullptr; //线程非安全版本 Singleton * Singleton::getInstance(){ if(m_instance == nullptr){ m_instance = new Singleton(); } return m_instance; }
因为构造和拷贝构造都是私有,那么说明该对象只能实例化一次
且均该变量一定为静态变量。
在多线程下,下面为不断优化,保证线程安全的各个迭代版本
//直接全局加锁 Singleton * Singleton::getInstance(){ Lock lock;//函数结束后直接释放 if(m_instance == nullptr){ m_instance = new Singleton(); } return m_instance; }
threadA和threadB必定阻塞,多线程安全,但是,影响性能
假设m_instance不是nullptr,多个线程进入,都是读操作而不是写操作,读操作是可以并发的(极高并发,如web服务器,很浪费)
//双检查锁 锁前锁后都检查 double check Singleton * Singleton::getInstance(){ if(m_instance == nullptr){ Lock lock;//函数结束后直接释放 if(m_instance == nullptr){ //一定要再判读一次,一面thread在进入第一个if后,再次出现被两个线程执行两次 m_instance = new Singleton(); } } //return 读的部分可以并发 return m_instance; }
但是以上内容依旧存在漏洞,内存读写会出现reorder的情况
m_instance = new Singleton(); //理论部分: //先分配内存 //调用构造器 //内存地址给m_instance //实际部分(有可能): //先分配内存 //内存地址给m_instance //调用构造器
当threadA执行到了实际的第二部,threadB进行,执行到了if判断,显然不为nullptr,毕竟已经把内存地址给了
然后threadB去使用这个m_instance,发生错误,因为threadA中并没有调用构造器
//C++ 11版本跨平台实现(volatile) std::atomic<Singleton> Singleton::m_instance; std::mutex Singleton::m_mutex; Singleton * Singleton::getInstance(){ Singleton * tmp = m_instance->load(std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_acquire);//获取内存 if(tmp == nullptr){ std::lock_guard<std::mutex> lock(m_mutex); tmp = m_instance->load(std::memory_order_relaxed); if(tmp == nullptr){ tmp = new Singleton; std::atomic_thread_fence(std::memory_order_release);//释放内存 m_instance->store(std::memory_order_relaxed); } } //return 读的部分可以并发 return tmp; }
要点总结
Singleton模式中的实例构造器可以设置为protected以允许子类派生。
Singleton模式一般不要支持拷贝构造函数和Clone接口,因为这有可能导致多个对象实例
这篇关于C++ 设计模式 单件模式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04el-table 开启定时器下,表格的选中状态会消失是什么原因-icode9专业技术文章分享
- 2024-10-03如何安装和初始化飞牛私有云 fnOS?-icode9专业技术文章分享
- 2024-10-03如何安装 App 并连接到飞牛 NAS?-icode9专业技术文章分享
- 2024-10-03如何安装飞牛 TV 并连接到影视服务器?-icode9专业技术文章分享
- 2024-10-03如何在PVE和ESXI上安装飞牛私有云 fnOS?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS安装系统异常情况处理-icode9专业技术文章分享
- 2024-10-03飞牛NAS如何创建存储空间?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS硬盘会自动休眠吗?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS如何安装飞牛影视和创建媒体库?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS如何为家人朋友开通影视账号?-icode9专业技术文章分享