0

0

C++如何实现单例模式?(保证全局唯一实例)

穿越時空

穿越時空

发布时间:2026-01-09 15:41:02

|

749人浏览过

|

来源于php中文网

原创

C++11起用static局部变量实现单例最安全,因编译器保证线程安全初始化;需禁用构造/拷贝/赋值,返回引用;异常或需控制销毁时改用std::call_once+std::unique_ptr。

c++如何实现单例模式?(保证全局唯一实例)

为什么static 局部变量实现最安全

现代 C++(C++11 起)中,static 局部变量的初始化是线程安全的——编译器会自动插入必要的同步机制,无需手动加锁。这是目前最简洁、最可靠的方式,避免了双重检查锁定(DCLP)中因内存重排序导致的未定义行为。

常见错误是仍用老式“懒汉+pthread_mutex”或“静态指针+new”,既冗余又易出错;更糟的是在构造函数里调用虚函数或依赖其他单例,可能触发静态初始化顺序问题。

  • 必须把构造函数、拷贝/移动构造、赋值操作全部设为 private
  • 禁止使用 new 手动分配——用上静态对象,由编译器管理生命周期
  • 不要返回 Singleton*,直接返回 Singleton& 更安全(避免空指针、误删)
class Singleton {
private:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;

public: static Singleton& getInstance() { static Singleton instance; // C++11 线程安全初始化 return instance; }

void doSomething() { /* ... */ }

};

什么时候不能用 static 局部变量?

当单例需要显式控制销毁时机(比如依赖其他全局对象析构顺序),或构造函数可能抛异常时,static 局部变量就不适用了——异常会导致初始化失败且后续调用永远抛 std::bad_function_call 或死锁。

立即学习C++免费学习笔记(深入)”;

此时应改用 std::unique_ptr + std::call_once,手动管理实例和销毁逻辑。

TemPolor
TemPolor

AI音乐生成器,一键创作免版税音乐

下载
  • std::call_once 保证初始化只执行一次,比手写锁更轻量
  • std::unique_ptr 可在程序退出前主动 reset(),避免析构顺序不可控
  • 必须用 std::atomicstd::once_flag,别用 bool + 手动 if 判断
class Singleton {
private:
    static std::unique_ptr instance;
    static std::once_flag initFlag;
Singleton() = default;
// ... 其他禁用函数同上

public: static Singleton& getInstance() { std::call_once(initFlag, [] { instance = std::make_unique(); }); return *instance; }

static void destroy() {
    instance.reset();
}

}; std::unique_ptr Singleton::instance = nullptr; std::once_flag Singleton::initFlag;

getInstance() 返回引用还是指针?

返回引用是默认推荐:语义清晰(单例必然存在)、避免空检查、防止用户误调用 delete。但若业务要求“允许未初始化状态”(比如配置未加载前不创建),就必须返回指针并接受 nullptr

注意:一旦返回指针,所有调用点都得做空值判断;而返回引用后,如果构造函数抛异常,getInstance() 后续调用会直接崩溃(C++ 标准规定:静态局部变量初始化异常后,再次访问会重新抛该异常)。

  • 95% 场景用 Singleton& 就够了
  • 若真要指针,用 std::shared_ptr 比裸指针更安全
  • 绝不要返回 Singleton* 并让用户负责生命周期

链接时重复定义 getInstance() 怎么办?

getInstance() 定义放在 .cpp 文件里,而不是头文件中 —— 否则多个源文件包含该头,会触发 ODR(One Definition Rule)违规,链接时报 “multiple definition” 错误。

常见做法是头文件只声明,.cpp 实现;或者用 inline(C++17 起)标记函数,允许在头文件中定义:

  • inline 最省事,但需确认编译器支持 C++17
  • 不用 inline 就必须拆头/实现,否则 Windows MSVC 和 Linux GCC 都会报错
  • 模板类单例天然内联,不受此限,但一般不建议模板化单例
// Singleton.h(C++17)
class Singleton {
public:
    inline static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }
    // ...
};

单例看似简单,真正难的是边界场景:构造异常、析构顺序、跨 DLL 边界、单元测试重置。多数人只写了“能跑”的版本,却没考虑模块解耦时它成了隐式依赖黑洞。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

723

2023.08.22

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

382

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

567

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

478

2023.08.10

空指针异常处理
空指针异常处理

本专题整合了空指针异常解决方法,阅读专题下面的文章了解更多详细内容。

22

2025.11.16

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

269

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

208

2023.12.29

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

565

2023.07.26

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

3

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.9万人学习

Git 教程
Git 教程

共21课时 | 2.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号