c++懒汉式单例模式(Singleton)多种实现方式及最优比较
前言
关于C++懒汉式单例模式的写法,大家都很熟悉。早期的设计模式中有代码示例。比如:
class Singleton {private: static Singleton *instance;public: static Singleton *getInstance() {if (NULL == instance)instance = new Singleton();return instance;}
};
它的缺点:线程不安全,指针资源没有释放。
自从C++11推出后,单例模式有了更优秀的写法,下面来介绍下。
使用 std::call_once 实现
#include <iostream>
#include <mutex>
#include <memory>class Singleton {
private:Singleton() { std::cout << "Singleton constructed." << std::endl; }static std::once_flag initInstanceFlag;static std::unique_ptr<Singleton> instance;// 删除拷贝构造函数和赋值操作符Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton& getInstance() {std::call_once(initInstanceFlag, []() {instance.reset(new Singleton());});return *instance;}void someMethod() {std::cout << "Method of the singleton" << std::endl;}~Singleton() {std::cout << "Singleton destructed." << std::endl;}
};std::once_flag Singleton::initInstanceFlag;
std::unique_ptr<Singleton> Singleton::instance;// 使用示例
void threadFunction() {Singleton& singleton = Singleton::getInstance();singleton.someMethod();
}int main() {std::thread t1(threadFunction);std::thread t2(threadFunction);t1.join();t2.join();return 0;
}
优点:线程安全、内存安全。显式控制初始化过程,适合需要延迟初始化的场景。
使用局部静态变量实现(C++11及以后)
#include <iostream>
#include <memory>class Singleton {
private:Singleton() { std::cout << "Singleton constructed." << std::endl; }// 关闭拷贝构造函数、右值拷贝构造函数和赋值操作符Singleton(const Singleton&) = delete;Singleton(const Singleton &&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton& getInstance() {static Singleton instance;return instance;}void someMethod() {std::cout << "Method of the singleton" << std::endl;}~Singleton() {std::cout << "Singleton destructed." << std::endl;}
};// 使用示例
void threadFunction() {Singleton& singleton = Singleton::getInstance();singleton.someMethod();
}int main() {std::thread t1(threadFunction);std::thread t2(threadFunction);t1.join();t2.join();return 0;
}
优点:线程安全。代码最简洁,由C++11标准保证线程安全,适合大多数场景。
缺点:适用于不复杂的工程。因为如果静态类之间有依赖,可能会导致C++的一些未定义的行为。
Meyers 的版本
Scott Meyers 是 Effective C++系列的作者,他最早提供了简洁版本的 Singletion 模型。根据他提供的模型,可以写出线程安全又简单的单例模式。代码如下:
#include <stdio.h>class singleton {static singleton &instance() {static singleton instance;return instance;} // instancesingleton(const singleton &) = delete;singleton & operator = (const singleton &) = delete;private:singleton() {}~singleton() {}public:void out(){ printf("out\n"); }
}; // struct singletonint main() {singleton::instance().out();return 0;
}
缺点:单一的实例总是在 main() 开始之前被初始化的,该实现无法做到 lazyinit。
优化版本:
template<typename T>class singleton {public:static T &instance();singleton(const singleton &) = delete;singleton &operator=(const singleton) = delete;protected:singleton() = default;};template<typename T>inline T &singleton<T>::instance() {static const std::unique_ptr<T> instance{new T{token{}}};return *instance;}
优点:线程安全、内存安全。
鸿蒙单例实现
线程安全、内存安全、双重检测、延迟加载、支持lazyinit、实现懒汉式单例模板。当前在商业(鸿蒙手机操作系统)使用中,代码可靠。
使用说明,请点这里。
下面只展示DelayedSingleton实现示例。完整代码以及其它几种单例实现,请点这里。
补充说明:对于懒汉式单例模式双重检测,有的人嫌代码麻烦,将构造函数私有化来实现。这个大家自己去评价。其实也没几行代码。写上双重检测,逻辑上也是提醒大家代码实现的风险点。不算优化问题。论可靠,还是相信鸿蒙吧。
template<typename T>
class DelayedSingleton : public NoCopyable {
public:static std::shared_ptr<T> GetInstance();static void DestroyInstance();private:static std::shared_ptr<T> instance_; instance.static std::mutex mutex_;
};template<typename T>
std::shared_ptr<T> DelayedSingleton<T>::instance_ = nullptr;template<typename T>
std::mutex DelayedSingleton<T>::mutex_;template<typename T>
std::shared_ptr<T> DelayedSingleton<T>::GetInstance()
{if (instance_ == nullptr) {std::lock_guard<std::mutex> lock(mutex_);if (instance_ == nullptr) {std::shared_ptr<T> temp(new (std::nothrow) T);instance_ = temp;}}return instance_;
}template<typename T>
void DelayedSingleton<T>::DestroyInstance()
{std::lock_guard<std::mutex> lock(mutex_);if (instance_ != nullptr) {instance_.reset();instance_ = nullptr;}
}
相关文章:
c++懒汉式单例模式(Singleton)多种实现方式及最优比较
前言 关于C懒汉式单例模式的写法,大家都很熟悉。早期的设计模式中有代码示例。比如: class Singleton {private: static Singleton *instance;public: static Singleton *getInstance() {if (NULL instance)instance new Singleton();return instanc…...

Gartner《2024中国安全技术成熟度曲线》AI安全助手代表性产品:开发者安全助手D10
海云安关注到,近日,国际权威研究机构Gartner发布了《2024中国安全技术成熟度曲线》(Hype Cycle for Security in China,2024)报告。 在此次报告中,安全技术成熟度曲线将安全周期划分为技术萌芽期(Innovation Trigger)…...

奇安信椒图--服务器安全管理系统(云锁)
奇安信椒图–服务器安全管理系统(云锁) 椒图 奇安信服务器安全管理系统是一款符合Gartner定义的CWPP(云工作负载保护平台)标准、EDR(终端检测与响应)、EPP终端保护平台(终端保护平台ÿ…...

pointer-events,添加水印的一个小小点
场景:平平无奇一个水印图,这类功能实现:就是覆盖在整个可视div后,又加了一个div(使用定位canvas画一个水印图充当背景),可时我好奇的是,我使用控制台,选择对应的元素时&a…...

微服务--认识微服务
微服务架构的演变 1. 单体架构(Monolithic) 阶段描述:在单体应用时代,整个应用程序被设计为一个项目,并在一个进程内运行。这种架构方式开发简单,便于集中管理,但随着应用的复杂化,…...

【docker】docker 镜像仓库的管理
Docker 仓库( Docker Registry ) 是用于存储和分发 Docker 镜像的集中式存储库。 它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。 Docker 仓库可以分为公共仓…...

第L2周:机器学习-线性回归
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 目标: 学习简单线性回归模型和多元线性回归模型通过代码实现:通过鸢尾花花瓣长度预测花瓣宽度 具体实现: (一&…...

SpringMVC拦截器深度解析与实战
引言 Spring MVC作为Spring框架的核心模块之一,主要用于构建Web应用程序和RESTful服务。在Spring MVC中,拦截器(Interceptor)是一种强大的机制,它允许开发者在请求处理流程的特定点插入自定义代码,实现诸如…...

直线上最多的点数
优质博文:IT-BLOG-CN 题目 给你一个数组points,其中points[i] [xi, yi]表示X-Y平面上的一个点。求最多有多少个点在同一条直线上。 示例 1: 输入:points [[1,1],[2,2],[3,3]] 输出:3 示例 2: 输入&am…...

经济管理专业数据库介绍
本文介绍了四个经济管理专业数据库:国研网全文数据库、EPS数据平台、中经网、Emerald全文期刊库(管理学)。 一、国研网全文数据库 国研网是国务院发展研究中心主管、北京国研网信息有限公司承办的大型经济类专业网站。国研网教育版”是国研…...

【C++ Primer Plus习题】11.1
问题: 解答: main.cpp #include <iostream> #include <fstream> #include "Vector.h" #include <time.h> using namespace std; using namespace VECTOR;int main() {ofstream fout;fout.open("randwalk.txt");srand(time(0));double d…...
[数据库][oracle]ORACLE EXP/IMP的使用详解
导入/导出是ORACLE幸存的最古老的两个命令行工具,其实我从来不认为Exp/Imp是一种好的备份方式,正确的说法是Exp/Imp只能是一个好的转储工具,特别是在小型数据库的转储,表空间的迁移,表的抽取,检测逻辑和物理…...

中国各银行流动性比例数据(2000-2022年)
介绍中国银行业2000年至2022年间的流动性比例数据,涵盖500多家银行,包括城市商业银行、城镇银行、大型商业银行、股份制银行、民营银行、农村合作银行、农村商业银行、农村信用社等。这些数据对于理解中国银行业的流动性状况至关重要,有助于投…...

MACOS安装配置前端开发环境
官网下载安装Mac版本的谷歌浏览器以及VS code代码编辑器,还有在App Store中直接安装Xcode(里面自带git); node.js版本管理器nvm的下载安装如下: 参考B站:https://www.bilibili.com/video/BV1M54y1N7fx/?sp…...

Docker 配置国内镜像源
由于 GFW 的原因,在下载镜像的时候,经常会出现下载失败的情况,此时就可以使用国内的镜像源。 什么是镜像源:简单来说就是某个组织(学校、公司、甚至是个人)先通过某种手段将国外的镜像下载下来,…...
AI模块在人工智能中扮演着什么样的角色
AI模块在人工智能(AI)中扮演着核心和关键的角色。它们是构成AI系统的基础单元,负责实现AI系统的各种智能功能。以下是AI模块在人工智能中扮演的具体角色: 功能实现的核心:AI模块集成了实现特定智能功能所需的算法、数据…...

VM Workstation虚拟机AlmaLinux 9.4操作系统安装(桌面版安装详细教程)(宝塔面板的安装),填补CentOS终止支持维护的空白
目录 AlmaLinux介绍 AlmaLinux操作系统的安装 1、下载镜像文件 2、新建虚拟机 (1)点击创建新的虚拟机 (2)打开虚拟机向导后,选择“自定义”安装,然后点击“下一步” (3)选择虚…...

【学习笔记】卫星通信NTN 3GPP标准化进展分析(三)- 3GPP Release17 内容
一、引言: 本文来自3GPP Joern Krause, 3GPP MCC (May 14,2024) Non-Terrestrial Networks (NTN) (3gpp.org) 本文总结了NTN标准化进程以及后续的研究计划,是学习NTN协议的入门。 【学习笔记】卫星通信NTN 3GPP标准化进展分析(一ÿ…...

【SQL】常见语句合集
SQL常见语句合集 一. 新建表1.1 语句1.2 结果 二. 新增数据2.1 语句2.2 结果 三. 新增字段列3.1 语句3.2 结果3.3 扩展 四. 更新指定数据4.1 语句4.2 结果 五. 更新指定列5.1 语句(长度) 六. 删除字段列6.1 语句 七. 删除指定数据7.1 语句 八. 查询 一. …...
Cozer必备!一站式解锁扣子全网最全插件集锦(三)
俗话说,工欲善其事必先利其器! 用过Coze的朋友都知道,插件在Coze里的重要性。插件库就相当于武器库,一个好的插件,就相当于一件趁手的兵器,可以让你事半功倍! 程哥精心整理了Coze最常用和好用…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...