C++11单例模式

c++11的三种单例模式

饿汉模式:在程序进入main函数之前就创建出了对象,不存在多线程的竞态关系,内存需要手动释放。优点是比较简单,容易实现,缺点是不能传入参数,占内存,不管用不用都创建出该对象。

懒汉模式:在程序需要的时候才会创建出对象,存在多线程竞态关系,需要用C++11std::call_oncestd::once_flag来避免竞态关系,内存需要手动释放。优点是不浪费内存,可以传入参数,缺点是实现比较复杂。

静态懒汉模式:和懒汉模式一样在程序需要的时候才会创建出对象,因为C++11保证了局部静态变量的初始化是串行的,所以不存在多线程竞态关系,对象存在于进程虚拟内存的静态区,不需要手动释放内存。优点是实现非常容易,创建对象的过程只需要两行代码,缺点是不能传入参数,因为不同参数数量会在编译期实例化出多个不同的函数,导致单例变成"多例"。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <iostream>
#include <mutex>
//--------------------------------饿汉模式--------------------------------
//方法与单例隔离,不相互依赖。
template<typename T>
class Singleton_Hungry {
private:
//将单例的构造函数私有化,目的是禁止其他程序创建该类的对象
Singleton_Hungry() = default;
~Singleton_Hungry() = default;
Singleton_Hungry(const Singleton_Hungry<T>&) = delete;
Singleton_Hungry(Singleton_Hungry<T>&&) = delete;
Singleton_Hungry<T>& operator=(const Singleton_Hungry<T>&) = delete;
Singleton_Hungry<T>& operator=(Singleton_Hungry<T>&&) = delete;
public:
static T* getInstance() { return m_instance; }
static void destroy() {
delete m_instance;
m_instance = nullptr;
}
private:
static T* m_instance;
};
template<typename T>
T* Singleton_Hungry<T>::m_instance = new T();

//--------------------------------线程安全懒汉模式1--------------------------------
//方法与单例隔离,不相互依赖,相比于饿汉,可以提供参数。
template<typename T>
class Singleton_Lazy1 {
private:
Singleton_Lazy1() = default;
~Singleton_Lazy1() = default;
Singleton_Lazy1(const Singleton_Lazy1<T>&) = delete;
Singleton_Lazy1(Singleton_Lazy1<T>&&) = delete;
Singleton_Lazy1& operator=(const Singleton_Lazy1<T>&) = delete;
Singleton_Lazy1& operator=(Singleton_Lazy1<T>&&) = delete;
public:
template<typename... Args>
static T* getInstance(Args&&... args) {
//std::call_once和std::once_flag,使得函数可以线程安全的调用一次。
std::call_once(m_flag, [&]() {
m_instance = new T(std::forward<Args>(args)...);
});
return m_instance;
}
static void destroy() {
delete m_instance;
m_instance = nullptr;
}
private:
static T* m_instance;
static std::once_flag m_flag;
};
template<typename T>
T* Singleton_Lazy1<T>::m_instance = nullptr;
template<typename T>
std::once_flag Singleton_Lazy1<T>::m_flag;

//--------------------------------线程安全懒汉模式2--------------------------------
//方法与单例隔离,不相互依赖,相比于懒汉模式1,优点是简单, 缺点是不能传参数。
template<typename T>
class Singleton_Lazy2 {
private:
Singleton_Lazy2() = default;
~Singleton_Lazy2() = default;
Singleton_Lazy2(const Singleton_Lazy2&) = delete;
Singleton_Lazy2(Singleton_Lazy2&&) = delete;
Singleton_Lazy2& operator=(const Singleton_Lazy2&) = delete;
Singleton_Lazy2& operator=(Singleton_Lazy2&&) = delete;
public:
static T* getInstance() {
//注意使用花括号,不然编译器会识别为函数声明;
static T m_instance{};
return &m_instance;
}
};

//-------------------------------------test----------------------------------------
class myTest {
public:
constexpr myTest(int a = 1,int b = 1)noexcept
:m_a(a),m_b(b){}
~myTest(){}
myTest(const myTest&)noexcept = default;
myTest(myTest&& rhs)noexcept = default;
myTest& operator=(const myTest&)noexcept = default;
myTest& operator=(myTest&&)noexcept = default;
public:
void multiply() {
std::cout << "a=" << m_a << " b=" << m_b <<" a*b=" << m_a * m_b << std::endl;
}
private:
int m_a;
int m_b;
};
int main()
{
std::cout << "饿汉单例" << std::endl;
myTest* pHungry1 = Singleton_Hungry<myTest>::getInstance();
pHungry1->multiply();
myTest* pHungry2 = Singleton_Hungry<myTest>::getInstance();
pHungry2->multiply();
std::cout << pHungry1 <<" "<< pHungry2 <<"\n" << std::endl;
Singleton_Hungry<myTest>::destroy();

std::cout << "懒汉单例1" << std::endl;
myTest* pLazy1 = Singleton_Lazy1<myTest>::getInstance(2,3);
pLazy1->multiply();
myTest* pLazy2 = Singleton_Lazy1<myTest>::getInstance();
pLazy2->multiply();
std::cout << pLazy1 << " " << pLazy2 <<"\n" << std::endl;
Singleton_Lazy1<myTest>::destroy();

std::cout << "懒汉单例2" << std::endl;
myTest* pLazyStatic1 = Singleton_Lazy2<myTest>::getInstance();
pLazyStatic1->multiply();
myTest* pLazyStatic2 = Singleton_Lazy2<myTest>::getInstance();
pLazyStatic2->multiply();
std::cout << pLazyStatic1 << " " << pLazyStatic2 << "\n" << std::endl;


return 0;
}


C++11单例模式
https://howl144.github.io/2022/03/22/00011. C++11单例模式/
Author
Deng Ye
Posted on
March 22, 2022
Licensed under