单例模式

最近看了很多关于单例模式的写法介绍,很多都有自己的特点,讨论的切入点也不一样。更重要的一点是高手讲解单例模式的时候,几乎不讲解为什么这么写(也就是语法上的意义)。今天就总结一下,和大家讨论一下。

第一中实现方法:

 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掉。前两种返回指针。

原文地址:https://www.cnblogs.com/OrdinaryMiracle/p/5001201.html