题目:实现单例(Singleton)模式
设计一个类,我们只能生成该类的一个实例
解析
题目要求明显,设计单例模式:仅生成单个实例
如此需要考虑一下几点:
- 构造函数需“隐藏”,且另设方法通过静态变量判断是否创建实例充当构造函数
- 返回实例的方法必定使用
new
创建实例(否则将产生值传递生成多个单例),故需存储静态实例指针待销毁时使用
- 静态变量用于存储变量创建状态,将其设为
int flag
?此举造成冗余,不如利用静态实例指针
理清三点后奉上本人渣码
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
| class Singleton { public: ~Singleton(); static Singleton* s_pInstance; static Singleton* getInstance(); private: Singleton(); }
Singleton* Singleton::s_pInstance = nullptr;
Singleton::Singleton() {}
Singleton::~Singleton() { if (nullptr != Singleton::s_pInstance) { delete Singleton::s_pInstance; Singleton::s_pInstance = nullptr; } }
Singleton* Singleton::getInstance() { if (nullptr == Singleton::s_pInstance) Singleton::s_pInstance = new Singleton(); return Singleton::s_pInstance; }
|
看似完美,却木有考虑多线程下同时执行 if (nullptr == Singleton::s_pInstance)
情况,加锁加锁……
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class LockBase { public: LockBase() { ::InitializeCriticalSection(&cs); } ~LockBase() { ::DeleteCriticalSection(&cs); } void lock() { ::EnterCriticalSection(&cs); } void unlock() { ::LeaveCriticalSection(&cs); } private: CRITICAL_SECTION cs; };
|
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
| class Singleton { public: ~Singleton(); static Singleton* s_pInstance; static Singleton* getInstance(); private: Singleton(); };
Singleton* Singleton::s_pInstance = nullptr;
Singleton::Singleton() {}
Singleton::~Singleton() { if (nullptr != Singleton::s_pInstance) { delete Singleton::s_pInstance; Singleton::s_pInstance = nullptr; } }
Singleton* Singleton::getInstance() { LockBase lockBase; lockBase.lock(); if (nullptr == Singleton::s_pInstance) Singleton::s_pInstance = new Singleton(); lockBase.unlock(); return Singleton::s_pInstance; }
|
very nice ! 😀 等等!其实这个锁的范围有点大了,我们可以再次优化,缩小范围
1 2 3 4 5 6 7 8 9 10 11 12
| Singleton* Singleton::getInstance() { if (nullptr == Singleton::s_pInstance) { LockBase lockBase; lockBase.lock(); if (nullptr == Singleton::s_pInstance) Singleton::s_pInstance = new Singleton(); lockBase.unlock(); } return Singleton::s_pInstance; }
|
不但缩小范围,而且提升效率,感觉很棒棒(๑•̀ㅂ•́)و✧ 对照下书本
有木有搞错!结果书上说还有更加优秀的解法=_=
力荐解法一:利用静态构造函数
静态构造函数:定义类时仅自动执行一次的函数
可能要让您失望了,书中使用C#,而C++没有静态构造函数!😂
先看看书中C#神级代码
1 2 3 4 5 6 7 8 9
| public class Singleton { private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } };
|
再看看 C++
模拟代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Singleton { public: ~Singleton(); static Singleton* s_pInstance; static Singleton* getInstance(); private: Singleton(); };
Singleton* Singleton::s_pInstance = new Singleton();
Singleton* Singleton::getInstance() { return Singleton::s_pInstance; }
|
其实是在全局域中直接设定,略显牵强😝
力荐解法二:实现按需创建实例
解法一中过早创建实例占用内存,所以可用高级语言中 类仅在使用时载入 的特性改进代码
C++无法实现此方法,以下依旧是书中C#神级代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Singleton { public static Singleton getInstance() { return Nested.instance; }
class Nested { internal static Singleton instance = new Singleton(); };
};
|
本题扩展
实现可继承单例,派生类都只能产生一个实例
可以在单例类中使用指针数组判断对应子类标记是否已存在,若存在直接返回,反之创建子类,应加锁实现




本文采用 CC BY-NC-SA 3.0 Unported 协议进行许可