不使用编译器扩展,不用C++11,不加锁,也不使用原子操作的话,那必须有个条件就是main函数执行之前程序必须是单线程的,不然真不行,再百度也不行,如果有符合以上条件的单例类且不要求main之前是单线程的,请告诉我....
然后:
这是2b单例:
template<typename T>
class Im2Bsingleton
{
public:
static T* get() {
if(ptr==nullptr) { ptr=new T; }
return ptr;
};
private:
static T* ptr;
};
这个显然不是线程安全的,因为ptr会在第一次被使用的时候new T,而第一次被使用的时候8成是main之后了,就很可能是多线程情况下,那么可以使用一个原子操作:
template<typename T>
class AtomicSingleton
{
public:
static T* get() {
for(;;) {
T* k=nullptr;
ptr.compare_exchange_weak(k,(T*)&place_holder);
if(k==0){
k=new T;
ptr.set(k);//此处必然成功
return k;
} else if(k==(T*)&place_holder) {
//别的线程占坑了,等着去吧!
} else {
return k;
}
}
};
private:
static atomic<T*> ptr;
static char place_holder;
};
代价是一次CAS和一次判断,但是题目说了不能加锁或者原子操作,那么,再说一遍就是必须保证
main函数执行之前不能存在多线程情况,可以这样:
template<typename T>
class Singleton
{
public:
static T* get() {
return ptr;
};
private:
static T* ptr;
};
你肯定觉得这个不对啊,ptr没被构造啊,对,保证前提的基础上,我们只需要保证ptr能在main之前绝逼
被构造就行了,我们需要一个helper:
普通单例:
template<typename T>
class Singleton
{
private:
struct ShitCleanHelper {
ShitCleanHelper(){ Singleton<T>::ptr=new T; }
~ShitCleanHelper(){
delete Singlenton<T>::ptr;
Singlenton<T>::ptr=nullptr;
}
};
public:
static T* get() {
return ptr;
};
private:
static T* ptr;
static ShitCleanHelper helper;
friend class ShitCleanHelper;
};
由于helper是static的,根据C++标准,静态对象被保证在main之前构造,因此ShitCleanHelper被绝对保证在main之前构造,它在构造时候不干任何事,只负责new T.这样,当进入main之后,ptr肯定就指着正确的对象了.
你会说那又不对了,这样虽然能够保证Singlenton在main之前new,但是万一我需要在main之前就要用get()怎么办? 又或者,我的模块与模块之间不同的static对象互相有交互,这一切都发生在main之前,怎么办?
下面是文艺单例:
template<typename T,bool DirectConstruction = true>
class ScopedSingleton
{
private:
class InstanceCreator {
public:
InstanceCreator() :m_ptr(new T) {};
~InstanceCreator() { delete m_ptr; };
operator T&() noexcept { return *m_ptr;}
private:
T* RESTRICT const m_ptr;
};
class DummyInstanceUser
{
public:
DummyInstanceUser(){ ScopedSingleton::getInstance(); }
~DummyInstanceUser() { ScopedSingleton::getInstance(); }
void DoNothing(){}
};
public:
static T& getInstance()
{
static InstanceCreator m_instancePtr;
m_dummyUser.DoNothing();
//此处似乎是模板的一个bug,加了这一句才能保证main之前m_instancePtr一定被构造.
return m_instancePtr;
};
private:
ScopedSingleton(){ getInstance(); }
~ScopedSingleton(){ getInstance(); }
private:
static DummyInstanceUser m_dummyUser;
};
首先,C++保证函数内的static变量保证在它第一次被使用之前被构造,这就避免了"普通单例"中可能在ShitCleanHelper构造new T之前就要使用的尴尬局面.无论什么时候要用它,它肯定会在这之前被构造了,但是这样一来又有问题了,假如main函数之前谁都不用它,而main之后才有人第一次用到它,那还怎么保证它在main之前被构造以避免多线程问题呢? 这就需要DummyInstanceUser出现了, DummyInstanceUser存在的唯一一个实例是m_dummyUser,由于它是static的,所以它保证了在main函数之前被构造,而它的构造函数的唯一目的就是"假装使用了m_instancePtr",这样即使没有人再main之前调用getInstance(),DummyUser依然会作为main之前的最后一道屏障保证在main之前一定构造成功.同时,这种单例还避免了跨模块的static变量互相引用的问题,例如有不同的单例A和B,它们在两个不同的cpp中,则它们的构造顺序虽然都在main之前,但互相之间的顺序是不确定的,但是使用这种文艺单例,如果A需要用到B,请看这一段文字的第一句话,只要A会用到B,B就会保证在A之前构造.
原网址: 访问
创建于: 2022-10-13 10:31:07
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论