Meyers‘ Singleton 最优单例(C++)

C++ 单例模式(Meyer‘s Singleton)实现 Scott Meyers 在 Effective C++ 的 Item 4: Make sure that objects are initialized before they’re used 里面提出了一种利用 C++ 的 static 关键字来实现的单例模式,这种实现非常简洁高效,它的特点是,仅当程序第一次执行到 GetInstance 函数时,执行 instance 对象的初始化. class Singleton { public: static Singleton& Instanc 阅读详情

🎯 Meyers' Singleton 是什么

Meyers' Singleton 是由 C++ 大师 Scott Meyers(《Effective C++》作者)提出的一种单例模式实现方式,核心就是利用 C++ 局部静态变量的特性来实现线程安全的单例。


📝 最简实现

cpp

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance;  // 核心:局部静态变量
        return instance;
    }
    
    // 禁用拷贝和赋值
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    
private:
    Singleton() {}   // 私有构造
    ~Singleton() {}  // 私有析构
};

就这么简单! 只有 5 行核心代码。


🔍 工作原理

1. 局部静态变量的特殊性质

cpp

static Singleton instance;

这个变量有以下几个特点:

特性说明
生命周期第一次执行到声明时创建,程序结束时销毁
存储位置静态存储区(不在栈上)
初始化时机第一次调用 getInstance() 时初始化(懒加载)
线程安全C++11 起,保证初始化过程是线程安全的

2. 执行流程示例

cpp

// 第一次调用
Singleton& s1 = Singleton::getInstance();
// ↓ 编译器生成类似这样的代码:
// 1. 检查是否已初始化(内部使用原子操作)
// 2. 如果未初始化:调用构造函数创建对象
// 3. 返回对象引用

// 第二次调用
Singleton& s2 = Singleton::getInstance();
// ↓ 直接返回已存在的对象引用(无锁、零开销)

🆚 对比传统实现

❌ 传统实现(有问题的版本)

cpp

class Singleton {
public:
    static Singleton* getInstance() {
        if (m_instance == nullptr) {      // 线程不安全!
            m_instance = new Singleton();
        }
        return m_instance;
    }
private:
    static Singleton* m_instance;
};

✅ Meyers' Singleton

cpp

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance;        // 线程安全 + 自动析构!
        return instance;
    }
};

核心区别:

  • 不需要手动管理指针

  • 不需要加锁

  • 不需要担心内存泄漏

  • 代码量减少 70%


🔒 为什么是线程安全的?

C++11 标准明确规定:

"具有静态存储期的局部变量的初始化是线程安全的。"

编译器的实现类似于:

cpp

// 编译器生成的伪代码
static Singleton& getInstance() {
    // 使用原子变量作为标志
    static std::atomic<bool> initialized = false;
    static char storage[sizeof(Singleton)];  // 原始内存
    
    if (!initialized.load(std::memory_order_acquire)) {
        // 加锁保证只有一个线程进入
        std::lock_guard<std::mutex> lock(mutex);
        if (!initialized.load(std::memory_order_relaxed)) {
            // 在 storage 上构造对象
            new (storage) Singleton();
            initialized.store(true, std::memory_order_release);
        }
    }
    return *reinterpret_cast<Singleton*>(storage);
}

关键点:

  • 使用双重检查锁定(Double-Checked Locking)的安全版本

  • 使用内存屏障防止重排序

  • 完全由编译器保证正确性


🎮 游戏服务器中的实际应用

示例 1:配置管理器

cpp

class ConfigManager {
public:
    static ConfigManager& getInstance() {
        static ConfigManager instance;
        return instance;
    }
    
    int getServerPort() const { return m_port; }
    void loadConfig(const std::string& path) { /* ... */ }
    
private:
    ConfigManager() { loadConfig("server.ini"); }
    int m_port = 8080;
};

// 使用
int port = ConfigManager::getInstance().getServerPort();

示例 2:日志系统

cpp

class Logger {
public:
    static Logger& getInstance() {
        static Logger instance;
        return instance;
    }
    
    void log(const std::string& msg) {
        std::lock_guard<std::mutex> lock(m_mutex);
        std::cout << "[LOG] " << msg << std::endl;
    }
    
private:
    Logger() { /* 打开日志文件 */ }
    ~Logger() { /* 关闭日志文件 */ }
    std::mutex m_mutex;
};

// 使用
Logger::getInstance().log("Server started");

示例 3:对象池

cpp

class ObjectPool {
public:
    static ObjectPool& getInstance() {
        static ObjectPool instance;
        return instance;
    }
    
    void* allocate(size_t size) { /* ... */ }
    void deallocate(void* ptr) { /* ... */ }
    
private:
    ObjectPool() { /* 初始化内存池 */ }
    ~ObjectPool() { /* 清理内存池 */ }
};

// 使用
void* mem = ObjectPool::getInstance().allocate(1024);

⚠️ 注意事项

1. 禁止拷贝

cpp

Singleton(const Singleton&) = delete;            // C++11
Singleton& operator=(const Singleton&) = delete;
// 或 C++98 风格:
// Singleton(const Singleton&);    // 只声明不实现
// Singleton& operator=(const Singleton&);

2. 使用引用而非指针

cpp

// ✅ 推荐:返回引用
static Singleton& getInstance();

// ❌ 不推荐:返回指针(容易忘记 delete)
static Singleton* getInstance();

3. 销毁顺序问题

cpp

// 问题:两个单例互相依赖销毁
class A {
public:
    static A& getInstance() { static A a; return a; }
    void doSomething() { B::getInstance().foo(); }  // 危险!
};

class B {
public:
    static B& getInstance() { static B b; return b; }
    void foo() { /* ... */ }
};

解决:尽量减少单例间的依赖,或在 main() 中显式控制创建顺序。


📊 性能对比

场景传统加锁实现Meyers' Singleton
首次调用需要加锁(~100ns)需要加锁(~100ns)
后续调用需要加锁(~100ns)零开销(无锁)
内存占用8字节指针 + 对象对象大小
代码行数~20行~5行

Meyers' Singleton 在后续调用时完全没有性能损耗,编译器会优化成直接返回地址。


🎯 面试回答范例

如果面试官问:"你知道哪些单例模式的实现方式?"

"我常用的是 Meyers' Singleton,这是 Scott Meyers 提出的实现方式,核心就是利用 C++11 的局部静态变量特性:

cpp

static Singleton& getInstance() {
    static Singleton instance;
    return instance;
}

它有几个优点:

  1. 线程安全:C++11 保证初始化过程是线程安全的

  2. 懒加载:第一次使用时才创建

  3. 自动析构:程序退出时自动调用析构函数

  4. 零开销:后续访问完全无锁

  5. 简洁:代码量极少,不易出错

相比传统的手动加锁和双重检查锁定,这个方案更安全、更高效。在我们的游戏服务器项目中,配置管理、日志系统、对象池等都是用这种方式实现的。"


📚 总结

要点说明
本质利用 C++ 局部静态变量的特殊性质
核心代码static T instance; 在函数内
线程安全C++11 起由标准保证
性能后续访问零开销
适用场景大多数单例需求
局限性无法控制析构时机,依赖关系需注意

Meyers' Singleton 是 C++ 中最优雅、最安全的单例实现方式,在游戏服务端开发中被广泛使用。掌握它,是成为 C++ 主程的基本功!🚀

17、科技领域的两位专家:Scott Meyers 与 Mike Lee 本文介绍了科技领域的两位专家 Scott Meyers 和 Mike Lee 的职业生涯、主要贡献以及他们的社交影响力。Scott 在计算机行业的多个领域都有涉猎,包括苹果技术推广、网页开发和书籍编辑;而 Mike Lee 专注于软件开发,并以开发 Delicious Library 和计划成立非营利性软件公司而受到关注。两人不仅在专业领域有突出表现,还体现了对家庭、团队和社区的感激,同时为我们的学习路径、价值观和社会交提供了重要的启示。 阅读详情

相关推荐

7 种单例模式实现方法大揭秘:从饿汉式到Meyers‘ Singleton

单例模式是软件设计中至关重要的一环,旨在确保一个类只有一个实例并提供全局访问点。它通过限制实例化的数量来避免资源浪费和不一致性问题,提高系统的灵活性和性能。本篇文章将全面探讨单例模式的各种实现方式,包括饿汉式、懒汉式、双重检查锁、Meyers' Singleton以及使用智能指针的方法。我们将深入分析每种实现的优缺点,帮助你在不同场景下做出最佳选择,并确保线程安全与资源管理的高效。通过本篇指南,你将掌握实现单例模式的最佳实践,提升你的编程技巧。

Lion_Long的博客 830

单例--Meyers' Singleton

C++单例–Meyers’ Singleton 简单写法 C++11以前需要双重检查,但是双重检查也是不安全的所以需要加锁;C++11以后,规定了local static在多线程条件下的初始化行为,要求编译器保证了内部静态变量的线程安全性.也就是说local static变量会在编译期初始化,我们可以利用这一特性完成单例. #include <iostream> #include &l...

weixin_44048823的博客 8675

[Effective.C.中文版].(Scott.Meyers).(中文版&第3版).pdf

[Effective.C.中文版].(Scott.Meyers).(中文版&第3版).pdf 个人收集电子书,仅用学习使用,不可用于商业用途,如有版权问题,请联系删除!

C++设计模式之单例模式(Singleton)

单例是一种创建型设计模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。保证一个类只有一个实例。为该实例提供一个全局访问节点。为什么会有人想要控制一个类所拥有的实例数量?最常见的原因是控制某些共享资源(例如数据库或文件)的访问权限。它的运作方式是这样的:如果你创建了一个对象,同时过一会儿后你决定再创建一个新对象,此时你会获得之前已创建的对象,而不是一个新对象。注意,普通构造函数无法实现上述行为,因为构造函数的设计决定了它必须总是返回一个新对象。

波风水门 3919

C#实战:如何用Chart控件打造专业级数据可视化报表(附完整代码)

本文详细介绍了如何使用C#的Chart控件创建专业级数据可视化报表,涵盖柱状图、饼图和雷达图等多种图表类型的高级定制与交互增强。通过完整的代码示例,展示了从环境配置到动态数据绑定的全流程,助力开发者提升企业级应用的数据可视化能力。

ipfs8storage的博客 423

idea 编译打包nacos2.0.3源码,生成可执行jar 包常见问题

idea 编译打包nacos2.0.3源码,生成可执行jar 包常见问题

fyihdg的专栏 1218

Singleton(单例模式)创建型

只涉及一个单一的类,该类否则创建自己的对象,同时确保只有单个对象被创建。这个类提供一种方法访问唯一的对象方式,可以直接创建,不需实例化该类的对象。保证一个类仅有一个实例,并提供一个访问它的全局访问点,主要解决一个全局使用的类频繁地创建与销毁。

weixin_50866517的博客 851

大陆毫米波雷达ARS408-21xx实战:从零搭建ROS环境下的目标检测与可视化

本文详细介绍了大陆毫米波雷达ARS408-21xx在ROS环境下的实战部署全流程。从硬件连接、CAN总线配置,到ROS驱动节点开发、CAN报文解析,再到RViz三维可视化实现,提供了完整的代码示例与调试技巧,帮助开发者快速搭建毫米波雷达目标检测与可视化系统。

open4的博客 634

Scott Meyers:C++史上最重要的五本书籍和五篇技术文章

 这几天Scott Meyers在artima上发起了C++书籍的大讨论,他给我们列了他认为最牛的五本经典书籍,依次是:The C++ Programming Language by Bjarne Stroustrup, Addison-Wesley, 1986 (1st edition), 1991 (2nd edition), 1997 (3rd edition), 2000 (spe

1万+

图自编码器(GAE)与变分图自编码器(VGAE)

在学习图自编码器之前先了解一下自编码器与变分自编码器。

小鱼的小窝 1万+

ConvNeXt 改进 :ConvNeXt添加GnConv递归门控卷积,二次创新CNBlock结构 ,独家首发

视觉 Transformer 在多种任务中取得了显著的成功,这得益于基于点积自注意力的新空间建模机制。视觉 Transformer 中的关键因素——即输入自适应、长距离和高阶空间交互——也可以通过卷积框架高效实现。作者提出了递归门控卷积(Recursive Gated Convolution,简称 gnConv),通过门控卷积和递归设计执行高阶空间交互。该新操作具有高度的灵活性和可定制性,兼容各种卷积变体,并将自注意力中的二阶交互扩展到任意阶数,而不会引入显著的额外计算。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 240

Scott Meyers给出的他认为C++史上最强的五篇文章

下面是Scott Meyers给出的他认为C++史上最强的五篇文章,最早的也要到97年了,反正除了Template Metaprograms有点印象其它是都没看过,打算抽时间把这些大牛推荐的Non-Book Publications再消化一下。 Programming in C++, Rules and Recommendations by Mats Henricson and Erik Ny

freerock 2734

基于STM32设计的盲人智能导盲杖

本设计基于STM32单片机,开发了一种面向视障人群的智能导盲杖系统。系统以STM32F103C8T6为核心控制器,集成了超声波测距、语音提示、环境光检测、GPS定位及4G通信等多种功能模块。

650

【Scott Meyers】C++5×5断想之四:C++历史上最重要人物

原文地址:http://www.artima.com/cppsource/top_cpp_people.html。译文发表于《程序员》2007.2。 作者介绍Scott Meyers,C++顶级权威之一,为世界各地客户提供培训和咨询服务。发表有畅销的Effective C++系列图书(《Effective C++》、《More Effective C++》和《Effective STL》)

8506

3060台式机 Ubuntu 双系统部署 LingBot-Map 完整指南

摘要: 本文详细介绍了在配备RTX 3060显卡的台式机上部署Ubuntu双系统并安装LingBot-Map 3D重建模型的完整流程。LingBot-Map作为蚂蚁灵波科技开源的Transformer架构模型,在流式3D场景重建中展现出高效性能(20 FPS)和卓越精度(ATE仅6.42米)。指南涵盖关键准备步骤、UEFI分区原理、Ubuntu安装流程(推荐150GB空间及手动分区方案),以及后续驱动配置说明,特别强调RTX 3060需12GB显存支持,并提供了数据备份、Secure Boot处理等实用建议

huanghm88的专栏 312

【PyQt】使用PyQt6基于Scenedetect制作视频场景自动分割应用

通过详细介绍PySceneDetect的功能和应用,本文阐释了如何利用这一工具提高视频编辑的效率。我们讨论了安装方法、命令行使用示例以及如何在Python脚本中集成PySceneDetect。此外文章还涵盖了基于PyQt6的图形界面设计,通过多线程技术处理视频,保证界面的响应性,并通过实时反馈机制提升用户体验。无论是专业的视频制作团队还是个人爱好者,PySceneDetect都提供了一种可行的、效率高的场景检测工具,让视频编辑工作变得更加简单快捷。

Mr数据杨 962

致敬:程序员成长路上的良师与经典著作

早上送孩子去幼儿园的路上,收到一个小伙伴的微信:我这才意识到今天是教师节!为人师,自觉还不够格!但在这个特殊的日子,作为IT行业从业人员,我想向那些在计算机科学和编程领域给予我们启迪的“老师们”致敬。这些老师可能不是传统意义上站在讲台前的教育者,但他们通过自己的著作、思想和贡献,通过他们的智慧结晶,为我们指明了方向,为无数程序员的成长之路点亮了明灯。这里我列举的作者与其著作也都是我个人从大学开始至...

TonyBai 1995

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

创建型模式——单例模式

单例模式 单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 基础要点 全局只有一个实例:static 特性,同时禁止用户自己声明并定义实例(把构造函数设为 private); 线程安全; 禁止赋值和拷贝; 用户通过接口获取实例:使用 static 类成员函数。 实现思路 私有化它的构造函数,以防止外界创建单例类的对象;使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态方法获取该实例。单例模式有两种实现方法,分别是懒汉和饿汉模式

lhq的博客 749

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

设计模式学习(一)单例模式的几种实现方式

简单讨论单例模式的几种形式

paw5zx的博客 1182

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Scott Meyers / Effective C++

Scott Meyers, 2015年退休,目前自己弄了个 Scott Meyers 软件开发咨询公司。 这位哥哥的 Effective C++ 与 More Effective C++ 确实写得好! 在琢磨(还不能说写, 从Java 到C++的转换还不适应)C++ 的过程中,发现有很多可用的选项, #define, const, Macro; String, char*; .... 总是不知道哪一个是最靠谱的。看网上很多资源,都推荐看一下 Effective 的两本书。 ...

cookiemaker的专栏 580

C++单例模式的演进:从经典实现到现代线程安全范式

摘要 本文系统梳理了C++单例模式的演进历程,从经典实现到现代线程安全范式。首先介绍了单例模式的基本概念与设计价值,包括资源控制和状态管理两大核心功能。随后详细分析了传统实现方式的问题:简单静态指针的非线程安全性、饿汉式的资源浪费问题,以及懒汉式双重检查锁定在C++11前的内存模型缺陷。重点阐述了现代C++的解决方案,特别是Meyers' Singleton的优雅实现,其利用C++11标准保证的静态局部变量线程安全初始化特性,成为当前最推荐的实现方式。此外还介绍了std::call_once和原子操作等替代

caowei880123的专栏 1089

C++ 单例模式 模版类(Meyers‘ Singleton)

自己实现的Meyers’ Singleton的单例模式模板类。 template<typename T> class Singleton { public: ~Singleton() = default; static T& getInstance() // Meyers' Singleton { static T instance; return ins...

xupeng1644的博客 3833

C++单例模式

设计模式中的单例模式适用于那些情景?如何使用C++实现单例模式?饿汉模式和懒汉模式?多线程条件下C++ local static 对象初始化。C++ non-local static 对象初始化次序问题。

riskLoveHe的博客 9084

c++历史上最重要的人物

C++断想:5x5系列之四 c++历史上最重要的人物 作者:Scott Meyers2006.8.30 摘要:在本文中,Scott Meyers向读者列举了他认为在C++发展历史中最重要的五个人物,并阐述了选择他们的理由。 在我的系列文章的前三篇中,我分别列举了c++历史上作出最重要贡献的图书,文献和软件:1、最重要的c++图书2、最重要的c++文献3、最重

何波的BO 2402

最安全的C++单例模式——Meyers’ Singleton

class Singleton { private: Singleton(); public: static Singleton&amp; getInstance() {     static Singleton instance;     return instance;     } }

脸红哥的博客 2790
上一篇: 纯虚析构函数(C++)
下一篇: 浅拷贝 vs 深拷贝 (C++)
second60
博客等级 码龄9年 155粉丝 88原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值