GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing notes.kamacoder.com — C++单例模式四种实现方式:饿汉式、懒汉式、双检锁与Magic Static的演进与选择 # C++ 单例模式的实现面试官问"怎么实现单例模式",大多数人能写出懒汉式,但追问"线程安全吗""双检锁有什么坑""现代 C++ 推荐哪种",就开始含糊了。 这道题考的不是能不能写出代码,而是你对四种实现方式的演进逻辑和各自的坑是否清楚。把"为什么一步步演进到 Magic Static"讲清楚,面试官就不会继续追了。 # 简要回答单例模式确保类只有一个实例 + 提供全局访问点。核心手段:构造函数私有化 + 删除拷贝/赋值 + 静态方法返回唯一实例。现代 C++ 推荐用局部静态变量(Magic Static): # 详细回答四种实现的演进逻辑 饿汉式:程序启动时就创建实例(静态成员变量在 main 之前初始化)。天然线程安全,但如果单例很重且可能用不到,就浪费了资源。另外多个饿汉式单例之间的初始化顺序不确定(static initialization order fiasco)。 懒汉式:第一次调用 双检锁(DCLP):在懒汉式基础上加锁。第一次检查避免每次都加锁(性能),加锁后第二次检查避免重复创建。但在 C++11 之前,由于指令重排和内存可见性问题,DCLP 实际上是有 bug 的。C++11 之后需要配合 Magic Static(C++11 推荐):函数内的局部 static 变量,C++11 标准规定其初始化必须是线程安全的(编译器负责加锁)。代码只需一行,没有手动锁、没有指针、没有内存泄漏(程序结束时自动析构)。这是现代 C++ 的标准答案。 为什么 Magic Static 是最优解 线程安全由编译器保证,不需要程序员操心。返回引用而非指针,不存在
# 知识拓展Q:单例模式有什么缺点?什么时候不该用? 单例本质是全局状态,会导致:单元测试困难(全局状态难隔离)、隐藏依赖关系(调用方看不出依赖了单例)、违反单一职责(既管业务又管自己的生命周期)。如果可以用依赖注入替代,优先不用单例。真正适合的场景:日志器、配置管理器、线程池、连接池——这些天然是全局唯一且生命周期贯穿整个程序的。 Q:双检锁在 C++11 之前为什么有 bug?
Q:饿汉式的初始化顺序问题是什么? 如果单例 A 的构造函数里用到了单例 B,而 B 还没初始化(不同编译单元的 static 变量初始化顺序未定义),就会崩溃。Magic Static 天然避免了这个问题——谁先被调用谁先初始化,顺序由调用链决定。 Q:单例怎么正确销毁? Magic Static 方式程序结束时自动析构,不需要手动管理。如果用指针式(饿汉/懒汉/双检锁),需要额外的销毁机制(如 评论验证登录状态... |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |