C++ —— 自动Singleton的实现

来源:互联网 发布:暴风王座坐骑进阶数据 编辑:程序博客网 时间:2024/04/29 10:21

这篇博客实现了一种自动的Singleton的设计模式的实现,相比起通常的Singleton的实现,这种方法更加简单而且更加灵活。

Singleton设计模式

单例模式在项目中是一种很重要的设计模式,它能保证一个对象在项目中只存在一个实例。在游戏中,例如说Texture Manager,Data Table这些东西应该都是从游戏开始时就创建一个实例,一直持续到游戏关闭。

Singleton往往被视为项目中的全局对象,因此相对于那些必须从属于某些事务的对象来说,全局对象的Singleton往往更加高效而且简便。否则,如果通过下面这种方式来获得一个TextureManager往往会让人崩溃:

GetApp()->GetServices()->GetGui()->GetTextureMgr();

当然,我们可以声明为外部连接全局范围的g_TextureMgr来访问。这样虽然的确很方便,但是由于全局对象的创建和销毁次序取决于执行时候的情况,对于那些可移植的项目,这些次序无法预计,因此效果还是不太好。

以往的方法

在教科书中,对于Singleton的管理通常如下:

TextureMgr& GetTextureMgr() {    static T s_Singleton;    return s_Singleton;}

当然为了方便,有些项目里面使用了模版或者宏,但是本质都是一样——在第一次调用的时候进行实例化,然后在程序解释的时候进行销毁。

但是这种做法有一个缺点在于是它无法控制资源的销毁——也就是说它必须在程序结束的时候才能释放掉。换句话说,我们对于资源的把控程度还不够。如果说我们想要在游戏运行的时候关闭掉一部分的话,那么这种做法显然是无法实现的。

换言之,我们需要能够追踪到这个资源,那么也就是需要找到指向它的指针。

有这么一种方法:

class TextureMgr {     static TextureMgr* ms_Singleton; public:     TextureMgr()     {        ms_Singleton = this;         // ...     }     ~TextureMgr()     {         ms_Singleton = NULL;         // ...    }     TextureMgr& GetSingleton()     {        return (*ms_Singleton);    } };

如果使用上面这种方法,就可以在任何时候创建以及销毁TextureMgr,而且也可以很方便地访问Singleton。

但是还有一点不方便,那就是用于追踪Singleton的代码需要加到每个类中,代码会显得比较累赘。

自动Singleton的实现

自动Singleton是使用模版来自动定义Singleton指针,并且完成指针设置、查询和清除的工作。它还可以使用assert来确保没有把Singleton实例化多次。

但是最重要的一点——只需要从这个类进行派生就可以获得Singleton的功能了

代码如下:

#include <cassert>template < typename T>class Singleton{     static T * ms_Singleton;public :     Singleton ()     {         assert (! ms_Singleton );         int offset = (int )( T*) 1 - ( int )(Singleton < T>*)( T *)1 ;        ms_Singleton = ( T *)( (int ) this + offset );     }     ~Singleton ()     {         assert ( ms_Singleton );         ms_Singleton = NULL ;     }     static T & GetSingleton ()     {         assert ( ms_Singleton );         return (* ms_Singleton );     }     static T * GetSingletonPtr ()     {         return ms_Singleton;     } };template < typename T >T * Singleton < T>:: ms_Singleton = 0 ;

上面代码中比较容易造成疑惑的地方是构造函数中的offset逻辑。这个涉及到对象比较和类型转化的问题了,在另一篇博客中又提到,传送门。

如果需要将任何类进行Singleton化,需要将其从Singleton进行公开继承即可。这种方法不会影响到类的大小,只会增加一些自动的函数调用。

当然,我们确保在使用前有对应的MyClass实例化。只要被实例化了,它就会被追踪。这样一来就可以使用MyClass::GetSingleton ()方法来获得这个对象。

<全文完>

0 0
原创粉丝点击