标签:
最近看了很多关于单例模式的写法介绍,很多都有自己的特点,讨论的切入点也不一样。更重要的一点是高手讲解单例模式的时候,几乎不讲解为什么这么写(也就是语法上的意义)。今天就总结一下,和大家讨论一下。
第一中实现方法:
1 class Singleton 2 { 3 private : 4 Singleton() 5 { 6 } 7 public : 8 static Singleton * instance() 9 { 10 if ( 0 == m_pInstance ) 11 { 12 m_pInstance = new Singleton(); 13 } 14 return m_pInstance; 15 } 16 private: 17 static Singleton * m_pInstance; 18 }; 19 Singleton* Singleton::m_pInstance = 0; 20 21 void fun(Singleton * p, Singleton *& q) 22 { 23 if(p == q) 24 { 25 cout << "right" <<endl; 26 } 27 return; 28 } 29 30 int main() 31 { 32 Singleton *ps = Singleton::instance(); 33 Singleton *ps1 = Singleton::instance(); 34 Singleton *ps2; 35 ps2 = ps; 36 37 if (ps2 == ps1) 38 { 39 cout << "right" << endl; 40 } 41 42 fun(ps, ps); 43 44 45 return 0; 46 }
分析一下第一种实现方法:
首先从语法上来分析:单例模式要求只能有一个实例,因此将这个实例封装成类之后,定义该类类型的成员。该成员定义为static类型,只能定义为指针类型或引用类型。返回实例的接口instance也定义为static,保证该实例之分配一个,且定义为static才可用类名直接调用,构造函数定义为私有的,保证不能创建新的对象。此外,并未声明且不定义构造函数和赋值操作符,实验证明不定义采用默认的不会产生新的实例,因为成员是指针类型,默认的构造函数和复制操作符是浅拷贝不会产生新对象。
优缺点分析:简单,易学。但是,该单例模式是线程不安全的。且该实例有可能被无意delete掉,之后再使用的实=实例就是新产生的了。那么该实例怎么delete呢?可以由用户负责delete掉,万一忘了呢?怎么破?
1 class Singleton 2 { 3 private: 4 Singleton() 5 { 6 } 7 8 class Garbo 9 { 10 public : 11 ~Garbo() 12 { 13 if (Singleton::m_pInstance) 14 { 15 delete m_pInstance; 16 } 17 } 18 }; 19 static Garbo garbo; 20 friend class Garbo; 21 public: 22 static Singleton * instance() 23 { 24 if ( 0 == m_pInstance) 25 { 26 m_pInstance = new Singleton(); 27 } 28 return m_pInstance; 29 } 30 31 private: 32 static Singleton * m_pInstance; 33 }; 34 Singleton* Singleton::m_pInstance = 0; 35 Singleton::Garbo Singleton::garbo; 36 37 void fun(Singleton * p, Singleton *& q) 38 { 39 if(p == q) 40 { 41 cout << "right" <<endl; 42 } 43 return; 44 } 45 46 int main() 47 { 48 Singleton *ps = Singleton::instance(); 49 Singleton *ps1 = Singleton::instance(); 50 Singleton *ps2; 51 ps2 = ps; 52 53 if (ps2 == ps1) 54 { 55 cout << "right" << endl; 56 } 57 58 fun(ps, ps); 59 60 61 return 0; 62 }
第二种带回收机制的单例模式的分析:
在单例类内定义一个内部类,内部类值实现析构函数,用于析构外部类的成员所指向的内存。原因:在外部类定义了内部类的static对象,在程序结束后会调用该静态类的析构函数,所以就可以实现析构了。需要注意的:需在外部类申明内部类为友员。须在类外初始化内部类类型的静态成员。
优缺点:有了无需用户参与的垃圾回收机制,但是依然是线程不安全的。(注:VC6.0 没有看到调用内部类的析构函数)
1 class Singleton 2 { 3 public : 4 static Singleton& Instance() 5 { 6 static Singleton instance; 7 return instance; 8 } 9 private : 10 Singleton() 11 { 12 13 } 14 Singleton(const Singleton &); 15 Singleton& operator=(const Singleton&); 16 };
第三种方法是《Effective C++》中的,将单例类定义为函数的static变量,每次返回的都是同一个实例。该方法实现简单,在有些环境下是线程安全的(具体我也不太清楚,sorry)。也不用担心垃圾回收。
作为一个菜鸟,只能写到这了,等日后学了多线程,再回来完善。
最后:获取实例的函数可以返回引用和指针两种情况,第三种方法我认为应该让返回引用,返回指针会破坏封装性,比如我们可以直接delete掉。前两种返回指针。
标签:
原文地址:http://www.cnblogs.com/OrdinaryMiracle/p/5001201.html