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

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

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

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

#include<stdio.h>
#include<iostream>
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 <<endl;
        }
private:
        Singleon(){};
        static Singleon *s;

};
Singleon* Singleon::s = NULL;
int main()
{
        Singleon::getinstance().Print("test");
        Singleon::getinstance().Print("test1");
        return 0;
}

在上面代码中,我们可以看到,两次调用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<stdio.h>
#include<iostream>
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 <<endl;
        }
private:
        class Cleaner
        {
                ~Cleaner()
                {
                        if(s != NULL)
                                delete s;
                }
        };
        static Cleaner clr;
        Singleon(){};
        static Singleon *s;

};
Singleon* Singleon::s = NULL;
int main()
{
        Singleon::getinstance().Print("test");
        Singleon::getinstance().Print("test1");
        return 0;
}

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

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

static Cleaner clr;

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


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

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

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

template <typename T>
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 <typename T>
T *singleton<T>::t=NULL;
template <typename T>
Lock singleton<T>::l;
template <typename T>
string singleton<T>::param="";

class Synonym:public singleton<Synonym>
{
};

class Adcode:public singleton<Adcode>
{
};

class District:public singleton<District>
{
};

咱们定义了三个单例化类了,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);



联想以后继续。。。


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

上一篇:python异常类型


下一篇:[EffectiveC++]item44:将与参数无关的代码抽离templates