标签:
单例模式的概念:
在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:保证一个类只有一个实例,并提供一个访问它的全局访问点。首先,需要保证一个类只有一个实例;在类中,要构造一个实例,就必须调用类的构造函数,如此,为了防止在外部调用类的构造函数而构造实例,需要将构造函数的访问权限标记为protected或private;最后,需要提供要给全局访问点,就需要在类中定义一个static函数,返回在类内部唯一构造的实例。
1 #include <iostream> 2 using namespace std; 3 class Singleton 4 { 5 public: 6 static Singleton* GetInstance(); 7 static void DestroyInstance(); 8 void getTest(); 9 private: 10 Singleton(){ m_test = 0; } 11 static Singleton* m_Instance; 12 int m_test; 13 }; 14 Singleton* Singleton::GetInstance() 15 { 16 if (m_Instance == NULL) 17 { 18 m_Instance = new Singleton(); 19 } 20 return m_Instance; 21 } 22 void Singleton::DestroyInstance() 23 { 24 if (m_Instance != NULL) 25 { 26 delete m_Instance; 27 m_Instance = NULL; 28 } 29 } 30 void Singleton::getTest() 31 { 32 cout << "m_test:"<<m_test << endl; 33 } 34 Singleton* Singleton::m_Instance = NULL; 35 int main() 36 { 37 Singleton *singletonTest = Singleton::GetInstance(); 38 singletonTest->getTest();
Singleton::DestroyInstance(); 39 getchar(); 40 return 0; 41 }
可能存在的问题:没有考虑多线程情况,在多线程情况下就有可能创建多个Singleton实例。
1 #include <iostream> 2 using namespace std; 3 class Singleton 4 { 5 public: 6 static Singleton* GetInstance(); 7 static void DestroyInstance(); 8 void getTest(); 9 private: 10 Singleton(){ m_test = 0; } 11 static Singleton* m_Instance; 12 int m_test; 13 }; 14 Singleton* Singleton::GetInstance() 15 { 16 if (m_Instance == NULL) 17 { 18 if (m_Instance==NULL) 19 { 20 lock(); //注意,此处加锁只是一个表示,具体使用boost或者其他库文件的接口 21 m_Instance = new Singleton(); 22 Unlock();//同上 23 } 24 25 } 26 return m_Instance; 27 } 28 void Singleton::DestroyInstance() 29 { 30 if (m_Instance != NULL) 31 { 32 delete m_Instance; 33 m_Instance = NULL; 34 } 35 } 36 void Singleton::getTest() 37 { 38 cout << "m_test:"<<m_test << endl; 39 } 40 Singleton* Singleton::m_Instance = NULL; 41 int main() 42 { 43 Singleton *singletonTest = Singleton::GetInstance(); 44 singletonTest->getTest();
45 Singleton::DestroyInstance(); 46 getchar(); 47 return 0; 48 }
备注:加锁部分代码进行了双重检测,判断条件是否为null,另外资源销毁时不用加锁,因为最后的资源销毁只需要最后使用的线程进行销毁回收即可,要是每个线程都进行销毁的话,会造成资源丢失和画蛇添足。
可能存在的问题:如果进行大数据操作的话,加锁行为就会成为一种瓶颈。
代码实现三:(避免线程加锁瓶颈)
1 #include <iostream> 2 using namespace std; 3 class Singleton 4 { 5 public: 6 static Singleton* GetInstance(); 7 static void DestroyInstance(); 8 void getTest(); 9 private: 10 Singleton(){ m_test = 0; } 11 static const Singleton* m_Instance; 12 int m_test; 13 }; 14 Singleton* Singleton::GetInstance() 15 { 16 if (m_Instance == NULL) 17 { 18 if (m_Instance==NULL) 19 { 20 lock(); //注意,此处加锁只是一个表示,具体使用boost或者其他库文件的接口 21 m_Instance = new Singleton(); 22 Unlock();//同上 23 } 24 25 } 26 return const_cast<Singleton*>(m_Instance); 27 } 28 void Singleton::DestroyInstance() 29 { 30 if (m_Instance != NULL) 31 { 32 delete m_Instance; 33 m_Instance = NULL; 34 } 35 } 36 void Singleton::getTest() 37 { 38 cout << "m_test:"<<m_test << endl; 39 } 40 const Singleton* Singleton::m_Instance = new Singleton(); 41 int main() 42 { 43 Singleton *singletonTest = Singleton::GetInstance(); 44 singletonTest->getTest(); 45 Singleton::DestroyInstance(); 46 getchar(); 47 return 0; 48 }
注意:改动的地方有两个,一个是将静态变量m_Instance声明为const并且进行了初始化,这样做的目的是在多线程中避免频繁加锁,节省开支。
但是如果不想进行实例的销毁,可以使用的成员变量不声明为指针,如下
1 #include <iostream> 2 using namespace std; 3 class Singleton 4 { 5 public: 6 static Singleton* GetInstance(); 7 void getTest(); 8 private: 9 Singleton(){ m_test = 10; } 10 int m_test; 11 }; 12 Singleton* Singleton::GetInstance() 13 { 14 static Singleton m_Instance; 15 return &m_Instance; 16 17 } 18 void Singleton::getTest() 19 { 20 cout << "m_test:"<<m_test << endl; 21 } 22 int main() 23 { 24 Singleton *singletonTest = Singleton::GetInstance(); 25 singletonTest->getTest(); 26 getchar(); 27 return 0; 28 }
番外篇:
实例销毁和内存释放
在类中,有一些文件锁了,文件句柄,数据库连接等等,这些随着程序的关闭而不会立即关闭的资源,必须要在程序关闭前,进行手动释放;
实例如下:
1 #include <iostream> 2 using namespace std; 3 class Singleton 4 { 5 public: 6 static Singleton* GetInstance(); 7 void getTest(); 8 private: 9 Singleton(){ m_test = 10; } 10 int m_test; 11 static Singleton *m_Instance; 12 class gc 13 { 14 public: 15 ~gc() 16 { 17 cout << "this is a test" << endl; 18 if (m_Instance!=NULL) 19 { 20 delete m_Instance; 21 m_Instance = NULL; 22 } 23 } 24 }; 25 static gc g; 26 }; 27 Singleton* Singleton::GetInstance() 28 { 29 30 return m_Instance; 31 32 } 33 void Singleton::getTest() 34 { 35 cout << "m_test:"<<m_test << endl; 36 } 37 Singleton* Singleton::m_Instance = new Singleton(); 38 Singleton::gc Singleton::g; 39 int main() 40 { 41 Singleton *singletonTest = Singleton::GetInstance(); 42 singletonTest->getTest(); 43 getchar(); 44 return 0; 45 }
在程序运行结束时,系统会调用Singleton的静态成员GC的析构函数,该析构函数会进行资源的释放,而这种资源的释放方式是在程序员“不知道”的情况下进行的,而程序员不用特别的去关心,使用单例模式的代码时,不必关心资源的释放。那么这种实现方式的原理是什么呢?我剖析问题时,喜欢剖析到问题的根上去,绝不糊涂的停留在表面。由于程序在结束的时候,系统会自动析构所有的全局变量,实际上,系统也会析构所有类的静态成员变量,就像这些静态变量是全局变量一样。我们知道,静态变量和全局变量在内存中,都是存储在静态存储区的,所以在析构时,是同等对待的。
由于此处使用了一个内部GC类,而该类的作用就是用来释放资源,而这种使用技巧在C++中是广泛存在的。
标签:
原文地址:http://www.cnblogs.com/jingliming/p/4445162.html