2008年11月19日

Singleton就是保证一个类只有一个实例,在Ogre里面有很多Singleton的例子,几乎所有的Manager都是Singleton的实例。比较下Gof里面的Singleton的实现和loki中的Singleton的实现,Ogre的Singleton算是比较简单的。Gof中实现一般是把类的构造函数给Private了然后再加上static的变量和函数实现的。下面来具体看一下Ogre中的Singleton
 1#ifndef _SINGLETON_H__
 2#define _SINGLETON_H__
 3
 4namespace Ogre {
 5    template <typename T> class Singleton
 6    {
 7    protected:
 8        static T* ms_Singleton;
 9    public:
10        Singleton( void )
11        {
12            assert( !ms_Singleton );
13#if defined( _MSC_VER ) && _MSC_VER < 1200     
14            int offset = (int)(T*)1 - (int)(Singleton <T>*)(T*)1;
15            ms_Singleton = (T*)((int)this + offset);
16#else
17        ms_Singleton = static_cast< T* >this );
18#endif
19        }

20        ~Singleton( void )
21            {  assert( ms_Singleton );  ms_Singleton = 0;  }
22        static T& getSingleton( void )
23        {    assert( ms_Singleton );  return ( *ms_Singleton ); }
24        static T* getSingletonPtr( void )
25        return ms_Singleton; }
26    }
;
27}

28#endif

先来看一下Singleton的构造函数是Public的,这样不是大家都能用了?往下看,第一句就是assert(!ms_Singleton); 如果ms_Singleton不是0的话,也就是Singleton<T>已经有了一个自己的对象,那么程序就死翘翘了。如果是0,那么跳过13-16行,直接看17行的
ms_Singleton = static_cast<T*>(this),有没有注意到那个this,出现在这里有点诡异。这里是构造函数,对象的初始化还没有完成呢,那么this指向的东西是什么呢?先来看一下怎么生成一个Singleton的实例。

#include <iostream>
#include 
"singleton.h"
class Intsin:public Singleton< Intsin >
{
public:
     Intsin(
int tmp):t(tmp){std::cout << "build"<< std::endl;}
    
~Intsin(){std::cout << "destory"<< std::endl;}
    print()
{std::cout << t << std::endl;}
private:
    
int t;
}
;

template
<> Intsin* Singleton< Intsin > ::ms_Singleton = 0;

int main()
{
    Intsin
* a;
    a 
=  new Intsin(3);
    a
->print();
    delete a;
    system(
"pause");
}
上面是一个超简单的实现,主要来看一下a = new Intsin(3);这里系统先按照Intsin的大小分配一块内存出来,然后调用Intsin的构造函数,当然要先运行基类Singleton<Intsin>的构造函数,这时Singleton构造函数的this指针应该是指向刚才分配的那个Intsin对象的地址了,虽然里面的东西不完整,但是this指向的对象的基本框架已经有了。所以可以这样使用它。要想知道这时this指针指向的对象到底有什么东西,什么东西没有,可以搜索一下“构造函数的this”看一下有关文章。当构造函数完成的时候,new返回一个指针。这样就完成了一个实例了。
下面来说一下,这个类什么东西没做,用的时候要注意什么。
1.当要实例化一个已经被实例化的类时,会有assert(!ms_Singleton);所以一定不能这样做。
2.对一个实例的指针两次调用delete也是让程序崩溃的好办法
3.Singleton<>不负责对象的解析,所以一定要记得自己delete,记住就一次。
总结下,这里的Singleton的实现比较简单,也很好用,但是程序员要负责的东西比较多。在Ogre中几乎所有的Singleton对象都是在root里面new和delete的。
就这么多吧。

posted @ 2008-11-19 11:07 空心菜 阅读(2392) | 评论 (1)编辑 收藏


2008年11月13日

看一下Ogre里面的ShagedPtr,其实就是一个Smart Pointers。下面的代码是删去了原有注释的。现不谈里面的MUTEX。

#ifndef __SharedPtr_H__
#define __SharedPtr_H__
#include "OgrePrerequisites.h"
namespace Ogre {
    template<class T> class SharedPtr {
    protected:
        T* pRep;           
        unsigned int* pUseCount; //看到这里,应该能知道,SharedPtr是通过引用计数来管理pRep的寿命      
    public:
        OGRE_AUTO_SHARED_MUTEX            
        SharedPtr() : pRep(0), pUseCount(0)
        {
            OGRE_SET_AUTO_SHARED_MUTEX_NULL
        }//允许有一个空的SharedPtr,不指向任何的对象。

        template< class Y>
        explicit SharedPtr(Y* rep) : pRep(rep), pUseCount(new unsigned int(1))
        {
            OGRE_SET_AUTO_SHARED_MUTEX_NULL
            OGRE_NEW_AUTO_SHARED_MUTEX
        }//这个写法是Member Templates,很有用,这样就允许用一个Y对象的指针来初始化一个SharedPtr<T>
                 //下面还能看到很多这样的Member Templates
                 //要是以前没见过的人,推荐看一下C++ Templates的第5章、第3节
                 //try this:   vector<int> intvec;
                 //       vector<float> floatvec;
                 //       floatvec = intvec ???????
                 //提一下,所有的初始化函数都没有检查rep是否非空,所以SharedPtr接受一个Null指针
                 //安全检查在每次调用的时候
                 //这里还使用了关键字explicit,禁止了隐式转换

        SharedPtr(const SharedPtr& r)
            : pRep(0), pUseCount(0)
        {
            OGRE_SET_AUTO_SHARED_MUTEX_NULL
            OGRE_MUTEX_CONDITIONAL(r.OGRE_AUTO_MUTEX_NAME)
            {
                OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
                OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
                pRep = r.pRep; //注意下与后面的不同
                pUseCount = r.pUseCount;
                // Handle zero pointer gracefully to manage STL containers
                if(pUseCount)
                {
                    ++(*pUseCount); 
                }
            }
        }

        SharedPtr& operator=(const SharedPtr& r) {
            if (pRep == r.pRep)
                return *this;
            SharedPtr<T> tmp(r);
            swap(tmp);
            return *this;
        }//这里的写法有点意思,本来在pRep指向r.pRep之前对pRep做一次release,
                 //但是这里没看到,其实是通过tmp这个局部变量的自动解析实现的。
        template< class Y>
        SharedPtr(const SharedPtr<Y>& r)
            : pRep(0), pUseCount(0)
        {
            OGRE_SET_AUTO_SHARED_MUTEX_NULL
            OGRE_MUTEX_CONDITIONAL(r.OGRE_AUTO_MUTEX_NAME)
            {
                OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
                OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
                pRep = r.getPointer(); //这里用的是函数,和上面那个的区别??
                pUseCount = r.useCountPointer();
                // Handle zero pointer gracefully to manage STL containers
                if(pUseCount)
                {
                    ++(*pUseCount);
                }
            }
        }
        template< class Y>
        SharedPtr& operator=(const SharedPtr<Y>& r) {
            if (pRep == r.pRep)
                return *this;
            SharedPtr<T> tmp(r);
            swap(tmp);
            return *this;
        }
        virtual ~SharedPtr() {
            release();
        }
        inline T& operator*() const { assert(pRep); return *pRep; }
        inline T* operator->() const { assert(pRep); return pRep; }
                //在用的时候检查pRep的合法性
        inline T* get() const { return pRep; }
        void bind(T* rep) {
            assert(!pRep && !pUseCount);
            OGRE_NEW_AUTO_SHARED_MUTEX
            OGRE_LOCK_AUTO_SHARED_MUTEX
            pUseCount = new unsigned int(1);
            pRep = rep;
        }
        inline bool unique() const { OGRE_LOCK_AUTO_SHARED_MUTEX assert(pUseCount); return *pUseCount == 1; }
        inline unsigned int useCount() const { OGRE_LOCK_AUTO_SHARED_MUTEX assert(pUseCount); return *pUseCount; }
        inline unsigned int* useCountPointer() const { return pUseCount; }
        inline T* getPointer() const { return pRep; }
        inline bool isNull(void) const { return pRep == 0; }
        inline void setNull(void) {
            if (pRep)
            {
                // can't scope lock mutex before release incase deleted
                release();
                pRep = 0;
                pUseCount = 0;
            }
        }

    protected:

        inline void release(void)
        {
            bool destroyThis = false;
            OGRE_MUTEX_CONDITIONAL(OGRE_AUTO_MUTEX_NAME)
            {
                OGRE_LOCK_AUTO_SHARED_MUTEX
                if (pUseCount)
                {
                    if (--(*pUseCount) == 0)
                    {
                        destroyThis = true;
                    }
                }
            }
            if (destroyThis)
                destroy();

            OGRE_SET_AUTO_SHARED_MUTEX_NULL
        }

        virtual void destroy(void)
        {
            delete pRep;
            delete pUseCount;
            OGRE_DELETE_AUTO_SHARED_MUTEX
        }

        virtual void swap(SharedPtr<T> &other)
        {
            std::swap(pRep, other.pRep);
            std::swap(pUseCount, other.pUseCount);
#if OGRE_THREAD_SUPPORT
            std::swap(OGRE_AUTO_MUTEX_NAME, other.OGRE_AUTO_MUTEX_NAME);
#endif
        }
    };

    template<class T, class U> inline bool operator==(SharedPtr<T> const& a, SharedPtr<U> const& b)
    {
        return a.get() == b.get();
    }

    template<class T, class U> inline bool operator!=(SharedPtr<T> const& a, SharedPtr<U> const& b)
    {
        return a.get() != b.get();
    }
}
#endif
最后有注意到:
    inline T* get() const { return pRep; }
    inline T* getPointer() const { return pRep; }
不知道为啥要这样,有一个不就行了么。
更多的细节、使用方法放到下次把。

posted @ 2008-11-13 17:37 空心菜 阅读(2484) | 评论 (3)编辑 收藏


仅列出标题  

posts - 2, comments - 4, trackbacks - 0, articles - 0

Copyright © 空心菜