记录一下 c++ 单例模式的实现方式。
饿汉模式
c++11 以后饿汉单例最好的方法是使用局部定义的 static 变量,因为 c++11 标准保证多线程初始化局部静态变量是线程安全的。
非模板的实现
GetInstance() 静态方法中定义一个局部静态变量,返回其指针即可。注意要把构造函数声明为私有,同时删除其拷贝构造函数、移动构造函数、拷贝赋值运算符、移动赋值运算符,保证不会以除 GetInstance() 方法以外的方式构造对象。
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
| #include <iostream>
class Singleton { public: static Singleton* GetInstance() { static Singleton instance; return &instance; }
private: Singleton() = default; Singleton& operator=(const Singleton&) = delete; Singleton(const Singleton&) = delete; Singleton& operator=(Singleton&&) = delete; Singleton(Singleton&&) = delete; };
int main() { Singleton* s1 = Singleton::GetInstance(); std::cout << s1 << std::endl;
Singleton* s2 = Singleton::GetInstance(); std::cout << s2 << std::endl;
return 0; }
|
模板实现
这里 Singleton 类的 GetInstance() 方法在构造 A 的局部静态变量的时候要用到 A 的构造函数,而 A 的构造函数已被声明为私有,故需要声明 Singleton 为 A 的友元类。
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
| #include <iostream>
template<typename T> class Singleton { public: static T* GetInstance() { static T instance; return &instance; }
private: Singleton() = default; Singleton& operator=(const Singleton&) = delete; Singleton(const Singleton&) = delete; Singleton& operator=(Singleton&&) = delete; Singleton(Singleton&&) = delete; };
class A { friend class Singleton<A>;
private: A() = default; A& operator=(const A&) = delete; A(const A&) = delete; A& operator=(A&&) = delete; A(A&&) = delete; };
int main() { A* s1 = Singleton<A>::GetInstance(); std::cout << s1 << std::endl;
A* s2 = Singleton<A>::GetInstance(); std::cout << s2 << std::endl;
return 0; }
|
懒汉模式
使用 std::call_once 配合 std::once_flag 保证多线程下初始化单例指针的线程安全。注意使用 std::call_once 在 GCC 环境下需要加 -pthread 编译选项,否则运行时会抛异常,使用旧版的 -lpthread 选项也是不行的。关于 -pthread 和 -lpthread 区别参考这篇文章
非模板实现
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
| #include <iostream> #include <thread> #include <mutex> #include <cassert>
class Singleton { public: static Singleton* GetInstance() { static std::once_flag s_flag; std::call_once(s_flag, []() { instance = new Singleton; }); return instance; }
private: Singleton() = default; Singleton& operator=(const Singleton&) = delete; Singleton(const Singleton&) = delete; Singleton& operator=(Singleton&&) = delete; Singleton(Singleton&&) = delete;
static Singleton* instance; };
Singleton* Singleton::instance = nullptr;
int main() { Singleton* instances[100] = {nullptr}; std::thread threads[100]; for(int i = 0; i < 100; i++) { threads[i] = std::thread([i, &instances]() { instances[i] = Singleton::GetInstance(); }); } for(int i = 0; i < 100; i++) { threads[i].join(); } Singleton* ins = instances[0]; for(int i = 1; i < 100; i++) { assert(instances[i] == ins); }
return 0; }
|
模板实现
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
| #include <iostream> #include <thread> #include <mutex> #include <cassert>
template<typename T> class Singleton { public: static T* GetInstance() { static std::once_flag s_flag; std::call_once(s_flag, []() { instance = new T; }); return instance; }
private: Singleton() = default; Singleton& operator=(const Singleton&) = delete; Singleton(const Singleton&) = delete; Singleton& operator=(Singleton&&) = delete; Singleton(Singleton&&) = delete;
static T* instance; };
template<typename T> T* Singleton<T>::instance = nullptr;
class A { friend class Singleton<A>;
private: A() = default; A(const A&) = delete; A(A&&) = delete; A& operator=(const A&) = delete; A& operator=(A&&) = delete; };
int main() { A* instances[100] = {nullptr}; std::thread threads[100]; for(int i = 0; i < 100; i++) { threads[i] = std::thread([i, &instances]() { instances[i] = Singleton<A>::GetInstance(); }); } for(int i = 0; i < 100; i++) { threads[i].join(); } A* ins = instances[0]; for(int i = 1; i < 100; i++) { assert(instances[i] == ins); }
return 0; }
|