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;
Singleon::Cleaner Singleon::clr;
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类的外面还得初始化下clr:

Singleon::Cleaner Singleon::clr;

现在这个单例类Singleon OK了,可以随便使用。保险起见,我们再看看内存检测的结果:

valgrind ./main
==15732== Memcheck, a memory error detector
==15732== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==15732== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==15732== Command: ./mainj
==15732== 
singleon str:test
singleon str:test1
==15732== 
==15732== HEAP SUMMARY:
==15732==     in use at exit: 0 bytes in 0 blocks
==15732==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated
==15732== 
==15732== All heap blocks were freed -- no leaks are possible
==15732== 
==15732== For counts of detected and suppressed errors, rerun with: -v
==15732== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)

其中:

==15732==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated
==15732== 
==15732== All heap blocks were freed -- no leaks are possible


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

是不是可以抽象下,把公共的东西定义到一个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);


参考:

单例模板类(静态单例模版类),还有另外一种设计,很精妙:

template <typename T>
class ssingleton
{
protected:
        struct object_creator
        {
                object_creator() { ssingleton<T>::instance(); }
                inline void do_nothing() const { }
        };
        static object_creator create_object;
        ssingleton(){};
public:
        typedef T object_type;
        static object_type & instance()
        {
                static object_type obj;
                create_object.do_nothing();
                return obj;
        }
        static object_type& getInstance()
        {
                return instance();
        }
};

template <typename T>
typename ssingleton<T>::object_creator ssingleton<T>::create_object;


联想以后继续。。。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

douban.com/note/356749278/
douban.com/note/356749293/
douban.com/note/356749305/
douban.com/note/356749318/
douban.com/note/356749326/
douban.com/note/356749334/
douban.com/note/356749341/
douban.com/note/356749354/
douban.com/note/356749363/
douban.com/note/356749384/
douban.com/note/356749468/
douban.com/note/356749484/
douban.com/note/356749503/
douban.com/note/356749523/
douban.com/note/356749556/
douban.com/note/356749593/
douban.com/note/356749611/
douban.com/note/356749646/
douban.com/note/356749666/
douban.com/note/356749695/
douban.com/note/356749817/
douban.com/note/356749830/
douban.com/note/356749853/
douban.com/note/356749867/
douban.com/note/356749883/
douban.com/note/356749927/
douban.com/note/356749967/
douban.com/note/356749984/
douban.com/note/356750045/
douban.com/note/356750069/
douban.com/note/356750191/
douban.com/note/356750216/
douban.com/note/356750230/
douban.com/note/356750262/
douban.com/note/356750287/
douban.com/note/356750304/
douban.com/note/356750311/
douban.com/note/356750324/
douban.com/note/356750344/
douban.com/note/356750386/
douban.com/note/356750438/
douban.com/note/356750453/
douban.com/note/356750485/
douban.com/note/356750504/
douban.com/note/356750536/
douban.com/note/356750557/
douban.com/note/356750561/
douban.com/note/356750584/
douban.com/note/356750596/
douban.com/note/356750606/
douban.com/note/356750682/
douban.com/note/356750713/
douban.com/note/356750731/
douban.com/note/356750769/
douban.com/note/356750770/
douban.com/note/356750784/
douban.com/note/356750828/
douban.com/note/356750839/
douban.com/note/356750848/
douban.com/note/356750859/
douban.com/note/356750933/
douban.com/note/356750952/
douban.com/note/356750980/
douban.com/note/356751001/
douban.com/note/356751031/
douban.com/note/356751052/
douban.com/note/356751064/
douban.com/note/356751072/
douban.com/note/356751087/
douban.com/note/356751100/
douban.com/note/356751172/
douban.com/note/356751203/
douban.com/note/356751225/
douban.com/note/356751240/
douban.com/note/356751263/
douban.com/note/356751284/
douban.com/note/356751295/
douban.com/note/356751303/
douban.com/note/356751315/
douban.com/note/356751325/
douban.com/note/356751359/
douban.com/note/356751373/
douban.com/note/356751383/
douban.com/note/356751392/
douban.com/note/356751402/
douban.com/note/356751416/
douban.com/note/356751428/
douban.com/note/356751451/
douban.com/note/356751476/
douban.com/note/356751511/
douban.com/note/356751564/
douban.com/note/356751572/
douban.com/note/356751588/
douban.com/note/356751594/
douban.com/note/356751615/
douban.com/note/356751649/
douban.com/note/356751689/
douban.com/note/356751725/
douban.com/note/356751747/
douban.com/note/356751778/
douban.com/note/356751843/
douban.com/note/356751850/
douban.com/note/356751861/
douban.com/note/356751871/
douban.com/note/356751889/
douban.com/note/356751896/
douban.com/note/356751909/
douban.com/note/356751943/
douban.com/note/356751964/
douban.com/note/356751999/

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值