C++ 中的 Meyer‘s Singleton

news/2025/10/31 17:27:24/文章来源:https://www.cnblogs.com/yubo-guan/p/19180681

目录
  • 1. 什么是 Singleton 模式?
  • 2. 传统的 Singleton 实现及其问题
  • 3. Meyer‘s Singleton:现代而优雅的解决方案
    • 实现代码
  • 4. Meyer’s Singleton 的工作原理与关键特性
  • 5. 使用方法
  • 6. 优点
  • 7. 潜在缺点与注意事项
  • 总结
  • 全局锁(单例模式)


1. 什么是 Singleton 模式?

Singleton(单例)是一种设计模式,其核心目标是确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。

2. 传统的 Singleton 实现及其问题

在 C++11 标准之前,实现一个线程安全的 Singleton 通常比较麻烦。常见的“双重检查锁定”模式虽然有效,但代码复杂,且在不正确的内存模型下容易出错。

// 传统的双重检查锁定 (复杂且容易出错,尤其在C++11之前)
class OldSingleton {
private:static OldSingleton* instance;static std::mutex m_mutex;OldSingleton() {} // 私有构造函数public:static OldSingleton* getInstance() {if (instance == nullptr) { // 第一次检查std::lock_guard<std::mutex> lock(m_mutex);if (instance == nullptr) { // 第二次检查instance = new OldSingleton();}}return instance;}// 删除拷贝构造和赋值操作OldSingleton(const OldSingleton&) = delete;OldSingleton& operator=(const OldSingleton&) = delete;
};// 在类外初始化静态成员
OldSingleton* OldSingleton::instance = nullptr;
std::mutex OldSingleton::m_mutex;

3. Meyer‘s Singleton:现代而优雅的解决方案

Meyer’s Singleton 是由 C++ 专家 Scott Meyers 在《Effective C++》中提出的。它利用了 C++ 标准中一个非常重要的特性:局部静态变量的初始化是线程安全的

核心思想:在函数内部定义一个静态局部对象,并直接返回它。

实现代码

class MeyerSingleton {
private:// 私有构造函数,防止外部创建实例MeyerSingleton() {std::cout << "MeyerSingleton constructed!" << std::endl;}// 私有析构函数(可选,但通常建议)~MeyerSingleton() {std::cout << "MeyerSingleton destroyed!" << std::endl;}public:// 删除拷贝构造函数和赋值操作符,确保唯一性MeyerSingleton(const MeyerSingleton&) = delete;MeyerSingleton& operator=(const MeyerSingleton&) = delete;// 关键的全局访问点static MeyerSingleton& getInstance() {static MeyerSingleton instance; // 核心:局部静态变量return instance;}// 一个示例成员函数void doSomething() {std::cout << "Doing something..." << std::endl;}
};

4. Meyer’s Singleton 的工作原理与关键特性

  1. 首次调用时构造

    • 当程序第一次调用 getInstance() 时,局部静态变量 instance 会被创建。
    • 后续调用都会直接返回这个已存在的实例的引用。
  2. 线程安全

    • 根据 C++11 及以后的标准(§[stmt.decl] §4),局部静态变量的初始化是线程安全的
    • 编译器会在底层自动为我们插入必要的锁或使用更高效的线程安全初始化机制(如 std::call_once),确保 instance 只被初始化一次,即使在多线程环境下。
  3. 自动析构

    • 静态局部变量在程序结束时(main 函数退出后)会自动析构。
    • 析构的顺序与它们构造的顺序相反。这有时可能会带来问题,如果 Singleton 的析构函数依赖于另一个已经被析构的全局对象(这就是所谓的“析构顺序问题”)。

5. 使用方法

int main() {// 获取单例实例的唯一方式MeyerSingleton& singleton = MeyerSingleton::getInstance();singleton.doSomething();// 再次调用,返回的是同一个实例MeyerSingleton::getInstance().doSomething();// 错误!构造函数是私有的,无法直接创建对象// MeyerSingleton s1;// 错误!拷贝构造函数被删除// MeyerSingleton s2 = singleton;return 0;
}

6. 优点

  1. 简洁优雅:代码量极少,意图清晰。
  2. 线程安全:无需手动处理锁,由 C++ 标准保证。
  3. 按需构造:只有在第一次被使用时才会创建实例,避免了程序启动时不必要的资源开销。
  4. 自动管理生命周期:无需手动 newdelete,避免了内存泄漏的风险。

7. 潜在缺点与注意事项

  1. 析构顺序问题

    • 如果 Singleton 在析构时,其成员函数被另一个正在析构的全局对象调用,可能会导致未定义行为。对于大多数不依赖其他全局对象的 Singleton 来说,这不是问题。
  2. C++11 之前不可用

    • 这种线程安全保证是 C++11 标准才引入的。在旧的编译器中,它可能不是线程安全的。
  3. 不可控的析构时机

    • 有时你可能希望 Singleton 的生命周期贯穿整个程序,或者在特定时刻手动销毁它。Meyer‘s Singleton 的析构时机是固定的(程序结束时),无法灵活控制。

总结

Meyer’s Singleton 是当今 C++(C++11 及以后)中实现 Singleton 模式的首选方法。它以其极致的简洁性、内置的线程安全性和自动的生命周期管理,几乎完全取代了那些复杂且容易出错的传统实现。

除非你有非常特殊的生命周期管理需求,或者需要在 C++11 之前的标准下工作,否则都应该使用 Meyer‘s Singleton。


全局锁(单例模式)

#include <mutex>class GlobalLock {
public:static GlobalLock& getInstance() {static GlobalLock instance;return instance;}void lock() {mutex_.lock();}void unlock() {mutex_.unlock();}bool try_lock() {return mutex_.try_lock();}// 删除拷贝构造函数和赋值运算符GlobalLock(const GlobalLock&) = delete;GlobalLock& operator=(const GlobalLock&) = delete;private:GlobalLock() = default;~GlobalLock() = default;std::mutex mutex_;
};

使用方式

// 使用方式
GlobalLock::getInstance().lock();
// 临界区代码
GlobalLock::getInstance().unlock();// 或者使用 lock_guard
std::lock_guard<std::mutex> lock(GlobalLock::getInstance().getMutex());

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/952032.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 比较数组数据大小

三目运算方式 public class 比较数组大小 {public static void main(String[] args) {int[] arr ={5,15,20,25,1000};for (int i = 0; i < arr.length-1; i++) { // System.out.println(Arrays.toStri…

lua+nginx用户鉴权脚本--get方法

需求: 一个应用暴露在外网,对登录用户做鉴权,相当于白名单用户. 原理: 用户在应用首页登录的时候会有get请求,在请求头中会有一串加密的base64字符串,经过jwt在线解码之后可以看到令牌过期时间,用户名以及其他信息,通过…

2025 年算法备案咨询服务公司最新推荐榜,技术实力与合规能力双维度权威测评解析

引言 2025 年算法备案进入 “双轨监管深化期”,《生成式人工智能服务管理暂行办法》等新规实施后,企业备案材料增至 8 项核心模块,双级审核流程使平均备案周期延长 40% 以上,合规难度显著提升。为精准筛选优质服务…

windows系统生成当日的时间戳文件脚本

@ECHO OFF echo.>"%date:~0,4%-%date:~5,2%-%date:~8,2% %time:~0,2%-%time:~3,2%-%time:~6,2%.txt"生成的格式 2022-11-13 15:11:23.txt 用法 新建一个bat文件 把内容拷贝进去即可 用途:我的日报一般在电…

docker中 Created和Exited状态容器导致磁盘空间爆满的处理的方式

完整的停止docker 容器服务docker stop 镜像运行id docker rm 镜像运行id当未对停止运行之后的容器进行rm之后 会占用大量磁盘空间 通过命令找到Created 和Exited状态的容器 并删除他们. for i in `docker ps -a |egre…

智能感应倒液器微波雷达方案和红外方案的优势和劣势

智能感应倒液器其实市面上一直都有,直到近些年才开始慢慢的进行规模性的普及。主要原因是一些公共场所的倒液器通过红外或者微波雷达做成智能无接触的会比较干净卫生。 以公共厕所为例无接触和有接触对比 手动公厕:你…

读完《代码大全2》

《代码大全2》快读完了,最后的部分在讲代码调整、系统和集成。读到这里,我对这本书的理解更深了一层。它教会我的不只是一些知识点,而是一种观念的转变:从“写代码”到“构建软件”。 “写代码”可能只关心一个函数…

2025 年闭式冷却塔,玻璃钢冷却塔,方形冷却塔,圆形冷却塔厂家最新推荐,实力品牌深度解析采购无忧之选!

引言 随着工业领域对冷却设备专业化、高效化需求的不断提升,闭式、玻璃钢、方形、圆形等不同类型冷却塔的市场关注度持续走高。为帮助企业精准筛选优质厂家,本次推荐榜单由制冷空调工业协会联合行业权威检测机构共同…

2025 年湖南冷却塔,长沙冷却塔,封闭式冷却塔,测试设备配套冷却塔厂家最新推荐,聚焦资质、案例、售后的五家机构深度解读

引言 随着湖南地区工业生产、中央空调及测试设备领域的快速发展,对冷却塔尤其是封闭式冷却塔、测试设备配套冷却塔的需求日益增长。为帮助企业精准筛选优质厂家,本次推荐榜单由制冷空调工业协会联合湖南省节能环保产…

2025年口碑好的积分球公司排名前十推荐:合肥金水木光电科技

文章摘要 随着光电检测技术的快速发展,积分球作为光学均匀化与光辐射测量的核心设备,在LED测试、光谱分析等领域需求持续增长。本文基于技术参数、市场口碑、服务能力等维度,对2025年国内积分球厂商进行综合排名,为…

积分球公司的信赖之选:十大好评如潮的靠谱厂家排行榜

文章摘要 随着光电检测技术的快速发展,积分球作为光学测量领域的核心设备,其市场需求持续增长。本文基于技术参数、市场口碑、服务能力等维度,对2025年国内积分球供应商进行综合评估,为行业用户提供选购参考。合肥…

在linux上使用perf火焰图

下载与解压 wget https://github.com/brendangregg/FlameGraph/archive/master.zip && unzip master.zip 或者 yum list perf yum -y install perf.x86_64出图perf record -F 99 -p 14623 -a -g -- sleep 60 …

Windows的hyper-v虚拟机设置静态IP,使用一段时间或者宽带网络变化后,出现宝塔面板页面时好时坏,有时正常,有时无法打开问题,bt status查看宝塔状态又是正常的

这个问题有两个原因,一是: 原来的"新建虚拟交换机"配置文件损坏,导致:ARP 表异常 宿主机与虚拟机之间二层通信中断 网络时好时坏解决方案:重建虚拟交换机 ✅ 1.新建一个虚拟交换机 +2.将虚拟机的网络适…

HT-LFCG-3800+

HT-LFCG-3800+HT-LFCG-3800+ 就是 Mini-Circuits 那颗 LFCG-3800+ 的国产肉身,LTCC 工艺把 DC 到 3.9 GHz 的通带做得像镜面一样平,4.5 GHz 处突然竖起 30 dB 的墙,2.4 GHz 插损低到 0.5 dB 出头,回波在通带里全程…

基础排序算法(六)希尔排序

基础排序算法(六)希尔排序一 希尔排序 希尔排序是一种非常独特且高效的排序算法,它通过一种“先宏观,后微观”的策略来提升效率 1.1 算法特性 1.2 算法原理 1.3 复杂度分析 1.4 使用场景 1.5 代码实现 1.6 常用算法…

2025 年集装袋厂家最新推荐榜:从技术创新到品质管控,深度解析行业优质企业的综合实力与市场竞争力内拉筋 / D 型导电 / C 型导电 / D 型防静电集装袋公司推荐

引言 2025 年工业包装行业发展报告显示,集装袋市场规模同比增长 12.3%,但产品质量差异导致的运输事故率仍占行业安全问题的 31%。为筛选出兼具性能与可靠性的优质品牌,包装联合会联合工业包装技术研究院开展专项测评…

英语词性

英语一共 8大词性(Parts of Speech),每个词在句子中扮演不同的语法角色👇 🧩 1️⃣ 名词 Noun 表示:人、事物、地点、抽象概念 例: people(人) city(城市) happiness(幸福) water(水) 🔹功能: 作主…

组织研磨仪厂家哪家好?2025年知名品牌推荐

在科学研究与工业应用中,组织研磨仪作为样品前处理的关键设备,其性能优劣直接影响到后续实验结果的准确性与可靠性。面对市场上琳琅满目的品牌与型号,如何挑选出最适合自身需求的组织研磨仪厂家,成为了众多科研工作…

openresty中使用ngx.sleep(0)防止worker进程阻塞

本文分享自天翼云开发者社区《openresty中使用ngx.sleep(0)防止worker进程阻塞》.作者:小谢不用谢 1. ngx.sleep(0)的工作原理 在OpenResty中,ngx.sleep(0)函数的作用是让当前的Lua协程主动放弃CPU执行权,以便Nginx…

Playwright定位元素与操作

Playwright 提供了多种灵活的元素定位和交互方式。下面这个表格汇总了其主要的元素定位方法、常见操作函数和一些进阶技巧:类别 方法/函数 说明元素定位方法 page.get_by_role() 通过角色(如button、link)定位page.…