C++中如何实现单例模式?

单例模式(Singleton Pattern)是一种设计模式,旨在确保一个类只有一个实例,并提供全局访问点。在 C++ 中实现单例模式有多种方式,下面介绍几种常见的实现方法。

1. 饿汉式(线程安全)

饿汉式是指在程序启动时就创建单例对象。这种方式实现简单,但不适用于创建过程较为复杂的对象。

示例:饿汉式单例模式
复制代码
#include <iostream>`

`class` `Singleton` `{`
`private:`
    `static Singleton instance;`  `// 声明静态实例`

    `// 构造函数和拷贝构造函数私有,防止外部创建对象`
    `Singleton()` `{`
`        std::cout <<` `"Singleton instance created!"` `<< std::endl;`
    `}`
    `Singleton(const Singleton&)` `=` `delete;`
`    Singleton&` `operator=(const Singleton&)` `=` `delete;`

`public:`
    `// 提供公共的静态方法来访问单例`
    `static Singleton&` `getInstance()` `{`
        `return instance;`
    `}`

    `void` `showMessage()` `{`
`        std::cout <<` `"Hello, Singleton!"` `<< std::endl;`
    `}`
`};`

`// 在类外定义静态实例`
`Singleton Singleton::instance;`

`int` `main()` `{`
`    Singleton& singleton1 =` `Singleton::getInstance();`
`    singleton1.showMessage();`

`    Singleton& singleton2 =` `Singleton::getInstance();`
`    singleton2.showMessage();`

    `return` `0;`
`}`
`
说明:
  • Singleton 类有一个静态成员 instance,在程序加载时就会创建它。
  • 构造函数、拷贝构造函数和赋值操作符是私有的,因此外部无法直接创建或拷贝 Singleton 对象。
  • getInstance() 提供了唯一的访问点来获取单例对象。

2. 懒汉式(线程不安全)

懒汉式是指在首次使用时才创建单例对象。这个方法的缺点是没有考虑线程安全性,可能在多线程环境下出现问题。

示例:懒汉式单例模式(线程不安全)
复制代码
#include <iostream>`

`class` `Singleton` `{`
`private:`
    `static Singleton* instance;`

    `// 构造函数和拷贝构造函数私有,防止外部创建对象`
    `Singleton()` `{`
`        std::cout <<` `"Singleton instance created!"` `<< std::endl;`
    `}`
    `Singleton(const Singleton&)` `=` `delete;`
`    Singleton&` `operator=(const Singleton&)` `=` `delete;`

`public:`
    `// 提供公共的静态方法来访问单例`
    `static Singleton*` `getInstance()` `{`
        `if` `(instance ==` `nullptr)` `{`
`            instance =` `new` `Singleton();`
        `}`
        `return instance;`
    `}`

    `void` `showMessage()` `{`
`        std::cout <<` `"Hello, Singleton!"` `<< std::endl;`
    `}`
`};`

`// 静态成员初始化为空指针`
`Singleton* Singleton::instance =` `nullptr;`

`int` `main()` `{`
`    Singleton* singleton1 =` `Singleton::getInstance();`
`    singleton1->showMessage();`

`    Singleton* singleton2 =` `Singleton::getInstance();`
`    singleton2->showMessage();`

    `return` `0;`
`}`
`
说明:
  • instance 是一个静态指针,首次调用 getInstance() 时创建单例对象。
  • 对于多线程程序,这种方式存在风险,因为多个线程可能同时通过 getInstance() 创建多个实例。

3. 线程安全的懒汉式(加锁)

为了确保在多线程环境下,懒汉式单例模式是线程安全的,可以使用互斥锁(mutex)来保证在多线程环境下的安全性。

示例:线程安全的懒汉式单例模式(加锁)
复制代码
#include <iostream>`
`#include <mutex>`

`class` `Singleton` `{`
`private:`
    `static Singleton* instance;`
    `static std::mutex mtx;`

    `// 构造函数和拷贝构造函数私有,防止外部创建对象`
    `Singleton()` `{`
`        std::cout <<` `"Singleton instance created!"` `<< std::endl;`
    `}`
    `Singleton(const Singleton&)` `=` `delete;`
`    Singleton&` `operator=(const Singleton&)` `=` `delete;`

`public:`
    `// 提供公共的静态方法来访问单例`
    `static Singleton*` `getInstance()` `{`
        `if` `(instance ==` `nullptr)` `{`
`            std::lock_guard<std::mutex>` `lock(mtx);`  `// 加锁,保证线程安全`
            `if` `(instance ==` `nullptr)` `{`
`                instance =` `new` `Singleton();`
            `}`
        `}`
        `return instance;`
    `}`

    `void` `showMessage()` `{`
`        std::cout <<` `"Hello, Singleton!"` `<< std::endl;`
    `}`
`};`

`// 静态成员初始化`
`Singleton* Singleton::instance =` `nullptr;`
`std::mutex Singleton::mtx;`

`int` `main()` `{`
`    Singleton* singleton1 =` `Singleton::getInstance();`
`    singleton1->showMessage();`

`    Singleton* singleton2 =` `Singleton::getInstance();`
`    singleton2->showMessage();`

    `return` `0;`
`}`
`
说明:
  • 通过在 getInstance() 方法中使用 std::mutex 进行加锁,确保在多线程环境下只有一个线程能创建单例对象。
  • 使用双重检查锁定模式:第一次检查 instance == nullptr 是为了避免不必要的加锁,第二次检查是在加锁后进行,确保只会有一个线程创建对象。

4. 使用 std::call_once 实现线程安全的单例模式

C++11 提供了 std::call_once 和 std::once_flag,可以在多线程环境下以更加高效的方式实现线程安全的单例模式。

示例:使用 std::call_once 实现线程安全的懒汉式单例
复制代码
#include <iostream>`
`#include <mutex>`

`class` `Singleton` `{`
`private:`
    `static Singleton* instance;`
    `static std::once_flag flag;`

    `// 构造函数和拷贝构造函数私有,防止外部创建对象`
    `Singleton()` `{`
`        std::cout <<` `"Singleton instance created!"` `<< std::endl;`
    `}`
    `Singleton(const Singleton&)` `=` `delete;`
`    Singleton&` `operator=(const Singleton&)` `=` `delete;`

`public:`
    `// 提供公共的静态方法来访问单例`
    `static Singleton*` `getInstance()` `{`
`        std::call_once(flag,` `[]()` `{`
`            instance =` `new` `Singleton();`
        `});`
        `return instance;`
    `}`

    `void` `showMessage()` `{`
`        std::cout <<` `"Hello, Singleton!"` `<< std::endl;`
    `}`
`};`

`// 静态成员初始化`
`Singleton* Singleton::instance =` `nullptr;`
`std::once_flag Singleton::flag;`

`int` `main()` `{`
`    Singleton* singleton1 =` `Singleton::getInstance();`
`    singleton1->showMessage();`

`    Singleton* singleton2 =` `Singleton::getInstance();`
`    singleton2->showMessage();`

    `return` `0;`
`}`
`
说明:
  • std::call_once 保证了某段代码(这里是创建单例对象)在多线程环境下只会执行一次,避免了线程安全的问题。

总结

  • 饿汉式 :类加载时即创建单例对象,线程安全,适用于简单对象。
  • 懒汉式(线程不安全) :只有在首次使用时才创建对象,不适用于多线程环境。
  • 懒汉式(线程安全) :通过互斥锁保证线程安全,但性能较差,适用于多线程环境。
  • std::call_once :通过 std::call_once 实现线程安全且性能较优的懒汉式单例模式。
相关推荐
FRing0331 分钟前
vue2干货总结8(路由模块封装、router-link、声明式导航、路由重定向、编程式导航)
开发语言·前端·vue.js·vue2
旖旎夜光33 分钟前
【C++ 基础入门】C++ 多态(上):虚函数、重写、override/final 与抽象类
开发语言·c++·笔记·学习
starzy19901 小时前
深入理解Scala嵌套函数:作用域封装之道
开发语言·scala
Sakura_j_h_1 小时前
从零写一个 MCP stdio Server:用 Python 校验博客文章格式
开发语言·python·自动化·ai工具·mcp·json-rpc
青少儿编程课堂2 小时前
蓝桥杯青少组图形化 STEMA 省考(报名倒计时·11/22开考)+ 全国青少年信息素养大赛 2026—2027赛季 + 电子学会图形化考级:校园华容道大闯关
c++·python·算法·bfs·信息学竞赛
白杨尚青3 小时前
C++进阶篇(五):红黑树——四条规则、三种插入情况与旋转变色
开发语言·数据结构·c++·stl·红黑树·平衡二叉树
.道阻且长.3 小时前
Linux基本开发工具:gdb和cgdb的使用
linux·运维·服务器·开发语言
starzy19903 小时前
深入理解Scala匿名函数:函数式编程基石
开发语言·scala
旖旎夜光4 小时前
【C++ 基础入门】C++ 继承(上):概念、切片、隐藏、默认成员函数与友元
c++·笔记·学习
apcipot_rain4 小时前
C++转Java日记(05)
java·开发语言·c++