单例模式
- 最简单的单例模式
1 //singelton.h文件 2 class CSingelton 3 { 4 public: 5 static CSingelton* getSingelton(); 7 private: 8 CSingelton(); 9 CSingelton(const CSingelton& other) = delete; 10 CSingelton& operator=(const CSingelton& other) = delete; 11 };
1 //singelton.cpp 2 CSingelton* CSingelton::getSingelton() 3 { 4 //线程安全 5 static CSingelton singleton; 6 return &singleton; 7 } 8 9 CSingelton::CSingelton() 10 { 11 12 }
期望用户通过getSingelton()来访问CSingelton的唯一实例, 但是用户可以将获得的指针付给其他变量,难以达到只能通过getSingelton() 来访问的目的。改进如下
2.只能通过getSingelton() 来访问简单单例
1 //singelton.h 2 class CSingelton 3 { 4 public: 5 static CSingelton& getSingelton(); 6 7 private: 8 CSingelton(); 9 CSingelton(const CSingelton& other) = delete; 10 CSingelton& operator=(const CSingelton& other) = delete; 11 };
1 //singelton.cpp 2 CSingelton& CSingelton::getSingelton() 3 { 4 //线程安全 5 static CSingelton singleton; 6 return singleton; 7 } 8 9 CSingelton::CSingelton() 10 { 11 12 }
达到了用户只能通过getSingelton()来访问CSingelton的唯一实例的目的。但如果这个唯一实例需要在堆上分配内存,1、2就不适用了。
3.在堆上分配的单例(饿汉模式)
1 //singelton.h 2 class CSingelton 3 { 4 public: 5 static CSingelton* getSingelton(); 6 7 private: 8 CSingelton(); 9 CSingelton(const CSingelton& other) = delete; 10 CSingelton& operator=(const CSingelton& other) = delete; 11 static CSingelton* m_pSingelton; 12 };
1 //singelton.cpp 2 3 CSingelton* CSingelton::m_pSingelton = new CSingelton; 4 CSingelton* CSingelton::getSingelton() 5 { 6 return m_pSingelton ; 7 } 8 CSingelton::CSingelton() 9 { 10 11 }
第一次访问实例前,单例已创建好,所以俗称饿汉模式。缺点是存在1)内存泄漏
4.在堆上分配的单例(懒汉模式)
1 //singelton.h 2 class CSingelton 3 { 4 public: 5 static CSingelton* getSingelton(); 6 7 private: 8 CSingelton(); 9 CSingelton(const CSingelton& other) = delete; 10 CSingelton& operator=(const CSingelton& other) = delete; 11 static CSingelton* m_pSingleton; 12 13 };
1 CSingelton* CSingelton::m_pSingleton = nullptr; 2 CSingelton* CSingelton::getSingelton() 3 { 4 if (nullptr == m_pSingleton) 5 { 6 m_pSingleton = new CSingelton 7 } 8 return m_pSingleton; 9 } 10 11 CSingelton::CSingelton() 12 { 13 14 }
由于第一次获取对象时才创建,所以俗称为懒汉模式。
缺点:1)此单例会造成内存泄漏,如何释放?2)单例构造不是线程安全的
5.线程安全懒汉模式单例
1 //safeSingelton.h 2 3 #include <mutex> 4 class CSafeSingelton 5 { 6 public: 7 static CSafeSingelton* getSingelton(); 8 9 private: 10 CSafeSingelton(); 11 CSafeSingelton(const CSafeSingelton& other) = delete; 12 CSafeSingelton& operator=(const CSafeSingelton& other) = delete; 13 static CSafeSingelton* m_pSingleton; 14 static std::mutex m_mtx; 15 16 };
1 //safeSingelton.cpp 2 3 CSafeSingelton* CSafeSingelton::m_pSingleton = nullptr; 4 CSafeSingelton* CSafeSingelton::getSingelton() 5 { 6 if (nullptr == m_pSingleton) 7 { 8 std::lock_guard<std::mutex> lock(m_mtx); 9 //此处第二次非空判断是必要的,因为第一次非空判断获取锁之后,其他线程可能已经将单例对像实例化出来了 10 if (nullptr == m_pSingleton) 11 { 12 m_pSingleton = new CSafeSingelton; 13 } 14 } 15 return m_pSingleton; 16 } 17 18 CSafeSingelton::CSafeSingelton() 19 { 20 21 }
此方式的缺点1)内存泄漏 2)将单例指针暴露在外