C++ 设计模式之单例模式学习及联想

2014-11-24 09:43:16 · 作者: · 浏览: 4

在高手的代码里面看到单例模式,觉得挺有意思,先整理学习下,然后利用自己的知识联想下,:)。

单例模式,是在工程里面,此类只能实例化一个对象,并且这个对象呢,全局共享的(只要include此类的头文件就可以了)。

先看看单例模式的实现吧:

#include
   
    
#include
    
      using namespace std; class Singleon { public: static string param; static Singleon& getinstance() { if(s == NULL) { s = new Singleon(); } return *s; } void Print(const char* str) { cout << "singleon str:" << str <
     
      
在上面代码中,我们可以看到,两次调用Singleon类的方法Print,只生成一个对象,按照一般的类的实现,就会生成两个对象,再调用其方法(当然这个例子,可以就一个对象,调用两次方法,如果是多个.cpp文件,就可以看出它的威力了)。

我们来编译此这段代码,可以把代码保持为文件名:main.cpp,编译如下:

g++ main.cpp -o main
valgrind ./main
==5627== Memcheck, a memory error detector
==5627== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5627== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5627== Command: ./mainj
==5627== 
singleon str:test
singleon str:test1
==5627== 
==5627== HEAP SUMMARY:
==5627==     in use at exit: 1 bytes in 1 blocks
==5627==   total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==5627== 
==5627== LEAK SUMMARY:
==5627==    definitely lost: 0 bytes in 0 blocks
==5627==    indirectly lost: 0 bytes in 0 blocks
==5627==      possibly lost: 0 bytes in 0 blocks
==5627==    still reachable: 1 bytes in 1 blocks
==5627==         suppressed: 0 bytes in 0 blocks
==5627== Rerun with --leak-check=full to see details of leaked memory
==5627== 
==5627== For counts of detected and suppressed errors, rerun with: -v
==5627== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)


细心地我们,很容易看出有一处内存分配了(如下),程序执行完,还没有释放,怎么办呢?

==5627== total heap usage: 1 allocs, 0 frees, 1 bytes allocated

程序中使用new实例化对象,需要使用delete释放对象,自始至终我们都没有使用delete,所以。。。

一种方法是实例化对象后,直接使用delete。这个方法有个问题是什么时候使用delete呢,每次使用都delete,那代价太大了,并且对于多线程程序,还容易出错。

下面就介绍另外一种方法,在单例会类中定义一个类,用于清空new的实例化对象。

#include
       
        
#include
        
          using namespace std; class Singleon { public: static string param; static Singleon& getinstance() { if(s == NULL) { s = new Singleon(); } return *s; } void Print(const char* str) { cout << "singleon str:" << str <
         
          

单例类Singleon中定义Cleaner类(如下),并实例化其静态对象,在程序结束的时候可以自动调用析构函数,进而调用delete。

class Cleaner
{
~Cleaner()
{
if(s != NULL)
delete s;
}
};

static Cleaner clr;

现在这个单例类Singleon OK了,可以随便使用。


如果一个类是单例类,直接使用上面的定义,没问题。如果有多个类呢,每个类都需要这样定义么,那代码的重复就多了。

是不是可以抽象下,把公共的东西定义到一个base类里面,每个单例类都继承它。单例类里面有个很重要的特性是初始化对象,base类只能初始化自己的对象,没法初始化子类的对象,还是有些问题。

这个时候就需要使用泛类的思想了。来看看代码:

template 
           
            
class singleton
{
        static Lock l;
        static T *t;
public:
        static string param;
        static T& instance()
        {
                if (t == NULL)
                {
                        l.lock();
                        if (t == NULL)
                        {
                                t = new T();
                        }
                        l.unlock();
                }
                return *t;
        }
        static T& getInstance()
        {
                return instance();
        }
};
template 
            
              T *singleton
             
              ::t=NULL; template 
              
                Lock singleton
               
                ::l; template 
                
                  string singleton
                 
                  ::param=""; class Synonym:public singleton
                  
                    { }; class Adcode:public singleton
                   
                     { }; class District:public singleton
                    
                      { };
                    
                   
                  
                 
                
               
              
             
            
           

咱们定义了三个单例化类了,Synonym,Adcode, District。代码不多,挺简洁的。

最后来看看这三个类的实例化:

Synonym::instance();
Adcode::instance();
District::instance();

//调用方法
Synonym::instance().Print(str);
Adcode::instance().Print(str);
District::instance().Print(str);

//当然也可以使用自己的方法
Synonym::instance().A(str);
Adcode::instance().B(str);
District::instance().C(str);



联想以后继续。。。