模板单例实现

#模板单例实现
本文参考 [用模板实现单例模式](http://blog.csdn.net/jnu_simba/article/details/9398465 "用模板实现单例模式") ,而且在此基础上作了适当的改进,使其支持更多功能。
    #ifndef Singleton_h__
    #define Singleton_h__
    template<class T>
    class Singletion
    {
    public:
    static T* GetInstance()
    {html

        static T m_Instance;linux

        return &m_Instance;
    }
安全

    private:
        Singletion(){};
        virtual ~Singletion(){};
        Singletion(const Singletion& ){};
        Singletion& operator=(const Singletion&){};
    };
    endif // Singleton_h__
    /*
具体使用方法以下:
    // 定义具体单例
       class CCenterImp
       {   
            public: // 构造函数要为public,不能为private和protect
                CCenterImp();     // 在构造函数中进行必要的初始化 
                ~CCenterImp ();  // 在析构函数中进行资源的释放
            private:
               // Method
                void print();
               // Variable
            }
        }
       typedef Singletion<CCenterImp> CCenter;
      // 使用单例方法
      CCenter::GetInstance()->print();
注意,要以typedef的方法来定义单例具体名称,具体单例CCenterImp的构造函数中初始化相关资源,在析构函数中释放相关资源。
提出问题1:为何不用双重double的方式?多线程

回答:双重double检查外加互斥锁的方式能够在知足获取要求,但何时释放申请的内存很差控制,如下是改进版双重检测函数

        if (NULL == m_pInstance).net

   {线程

    // Lock相关指针

    if (NULL == m_pInstance)htm

    {对象

      T* temp = new T();  // 先new一个示例出来赋给临时变量

      m_pInstance = temp;  // 在赋值给真实的变量

    }

   }

  return m_pInstance;

    若是不须要作成模板复用的话,能够在此单例子中在增长一个内部嵌套静态类,在其析构函数中释放这里申请的内存,但若是要作成模板类的话,这个内嵌类就无法实现了,所以放弃这种方式。

思考2:对于new出一个单例的方式,如何放置释放处理函数。

回答: 参考网上的处理,有atexit函数,此函数是<stdlib.h>中的函数,能够注册一系列函数,用于在main函数退出后执行,在单例实例很少的状况下,能够考虑使用,但必定要注意它自身的限制,ISO C规定,一个进程在退出时,最多能够注册32个atexit函数,这些函数依次被exit函数所调用,若是要作成模板单例,供其余模块使用,就会有数量上的限制。 

思考3:对于new出来的实例,尝试保存它自身以及相关析构函数,在系统销毁时,统一调用一次。

回答:今天曾尝试着将new出来的实例地址以及它对应的析构函数地址存放在map中,存放在另外一个单例中,等系统快要退出时统一显示调用调用。这里有2个问题,一个是多个不一样的单例实例,只能以void*的形式保存其指针,在准备调用delete时,指针保存的类信息丢失了,没法调用到其析构函数。 网上有利用汇编技巧的方法获取析构函数的地址,参考连接:http://www.cnblogs.com/findumars/p/3746869.html, 我尝试了下,执行到析构函数时发生崩溃了,尝试了多种方式,仍是不行,此路不通。

思考4:单例类能够在外部new一个出来或者在本地定义一个局部变量吗?

回答:由于要构造一个单例类,因此这个单例类的构造函数必定不能是private或者是protect类型的,可是,这样一类,就能够直接在外部定义这样一个类了,无论你是在单例的GetInstance里面new出来,仍是 局部静态变量出来,都须要构造函数。

思考5: 局部静态变量的单例模式需不须要加锁?

回答: 参考此篇文章,http://blog.csdn.net/yichigo/article/details/37878117, 若是加锁保护,那么之后每次调用GetInstance都会有锁,若是不加锁,若是构造函数中执行的时间较长,在多线程环境下,可能会这个变量构造到一半,就被另外一个线程拿过去用了。为了平衡这两种状况,在程序中,对于此单例有可能有多线程访问的状况下,在程序启动初始化时,显示调用一个CCenter::GetInstance(),手动触发初始化操做后,而后开启多线程,这样,既保证了在多线程工做时,此单例确定是初始化完成了,在获取时,也不须要加锁,快速直接。备注:局部静态变量的线程安全性,在C++0x上的编译器能够保证,在linux平台下的gcc编译器能够保证,在低版本的VC下不保证,所以,不要把这个变化的部分推给编译器。在程序初始化时,显示调用一次,确保构造完成后,再开启多线程相关工做,咱们是能够掌控这种状况的。

思考6: 对于上文提出的,静态局部变量的方式,有一点要注意,模板类里面的构造、析构、拷贝构造、赋值要设置private,实现类里面的构造要设置为public,不能设置为protect和private。这里有一个小缺陷,用户能够定义或者new CCenterImp 类,但不能定义或者new CCenter类。整个单例对外表现的对象为CCenter类,可是,CCenterImp只能定义在头文件里面,这样,别人看到了就有误用的可能,想来想去,也没想到什么好的方法,只能经过注释文字说明来提示使用者,使用CCenter类,而不要直接使用CenterImp类。

    好了,关于单例的思考和讨论汇总为这么多,之后在使用时,若是须要复用,就用上述提到的模板类,若是不须要复用,简简单单一个局部静态变量加上手动初始化,可确保万事大吉。

相关文章
相关标签/搜索