引言
在业务逻辑中,常需确保某个对象在多线程中仅被创建一次,那么,如何实现呢?答案就是单例模式,本文章将对懒汉单例进行详细介绍
局部静态变量(函数内声明的静态变量)
对于局部静态变量,其显著特征就是函数因多次调用导致静态变量定义语句被重复执行时,只有第一次调用时进行初始化操作,后续该函数的重复调用将会跳过该语句,而该特征对于类内成员函数中的局部静态变量依旧成立,具体来说:
cpp
// 成员函数的局部静态变量行为测试
class Test
{
public:
void test()
{
static int a{};// 与全局函数的静态局部成员行为完全一致,当该语句因函数的多次调用而被重复执行时,只有第一次调用时进行初始化操作
cout << ++a << "\n";
}
};
void test1()
{
Test{}.test();// 1
Test{}.test();// 2
Test{}.test();// 3
}
运行结果表明:a 只被初始化一次,并在多次调用间保持状态 ,这为"延迟初始化"提供了天然的语言级支持
懒汉单例
懒汉单例就需要借助局部静态变量的上述特点进行实现,代码如下:
cpp
// 受上述启发得到的单例模式设计与测试
class MyClass
{
public:
static MyClass& Instance()// 获取单例的函数必须设计为静态,原因是,若非静态,则需要实例才能调用,而若具备实例也就不需要调用该函数了
{
static MyClass mC{};// 核心,创建局部静态变量作为单例
return mC;
}
~MyClass() = default;
// 设计单例模式,需要将拷贝以及赋值重载进行delete
MyClass(const MyClass& other) = delete;
MyClass& operator=(const MyClass& other) = delete;
// 注:若显式delete拷贝构造及赋值重载,则对应的移动语义不会再自动生成,这里为了代码语义清晰性仍显示进行了移动语义delete
MyClass(MyClass&& other) = delete;
MyClass& operator=(MyClass&& other) = delete;
void test()
{
cout << _a++ << "\n";
}
private:
MyClass() = default;// 将构造函数设计为私有成员,确保只有类的成员可以访问(包括静态成员)
int _a{};
};
void test2()
{
MyClass& mC1 = MyClass::Instance();// 如此设计的单例,需使用引用类型接收
mC1.test();// 0
mC1.test();// 1
MyClass& mC2 = MyClass::Instance();
mC2.test();// 2
mC2.test();// 3
}
可以看到,mC1 和 mC2 实际上引用的是同一个对象。
设计要点解析
1. Instance() 为什么必须是 static
如果 Instance() 是非静态成员函数:
- 调用它需要一个对象实例
- 但获取实例正是我们调用它的目的
这就形成了逻辑死循环。
因此,获取单例的接口必须是 static。
2. 为什么要把构造 / 拷贝 / 移动全部封死
| 函数 | 原因 |
|---|---|
构造函数 private |
防止外部随意构造对象 |
拷贝构造 = delete |
禁止逻辑上不合理的复制 |
拷贝赋值 = delete |
同上 |
移动构造 / 赋值 = delete |
显式表达"不可移动",避免隐式规则带来的误解,提高代码可读性 |
显式
= delete是一种防御性编程手段,比"依赖编译器隐式行为"更清晰、更安全
3. 为什么构造函数可以是私有的?
虽然构造函数是 private,但:
Instance()是类的静态成员- 静态成员可以访问类的私有成员
因此,static MyClass mC{}; 是完全合法的。
一个非常重要的线程安全说明(C++11+)
- C++11 之前 :函数内静态变量初始化不是线程安全的,多线程并发可能导致多次初始化。
- C++11 起 :标准明确规定,函数内静态变量初始化是线程安全的 (俗称 Magic Statics)。
因此,这种单例写法要求编译环境至少为 C++11。
小结
- 本实现是懒汉式单例
- 基于函数内静态变量(Meyers Singleton)
- C++11 起天然线程安全
- 无锁、无手动内存管理、生命周期由语言保证
这也是 Scott Meyers 在 Effective C++ 中推荐的单例实现方式,被广泛认为是现代 C++ 中最优雅的单例写法之一