关闭

C++ 单例模式

238人阅读 评论(0) 收藏 举报
分类:

单例模式Singleton(),应该是设计模式中最简单的一种模式,表明在整个程序执行周期内,类的实例对象只能存在一个。虽然很简单,但是应用场景却是很多,比如windows的任务管理器;windows的回收站,在整个系统运行中,回收站一直维护着一个实例;应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。

UML_Singleton

class CSingleton
{
public:
    static CSingleton* getInstance()
    {
        if (m_pInstance == NULL)
        {
            m_pInstance = new CSingleton;
        }

        return m_pInstance;
    }

protected:
    CSingleton() {}
    virtual ~CSingleton() {}

private:
    static CSingleton* m_pInstance;
};

CSingleton* CSingleton::m_pInstance = NULL;

上面的代码是最简单的一种单例模式实现,主要有几个地方需要注意。首先是单例模式只能通过getIntance() 实现,而不能通过构造函数的方式实现,所以必须设置构造函数是私有的或者保护的。其次,既然只能在整个程序运行周期存在一个对象,那么私有的成员变量应该设置为静态变量,同理,那么函数的修改也应该是静态。静态成员变量只能在类外显示声明,因为它不属于某一个对象,而属于这个类共享。


程序代码最终是希望有良好的扩展性和稳定性,如果上面的代码在多线程环境中,肯定不能保证实例对象只存在一个,所以需要修改在多线程中是满足单例模式的定义。其次,单例模式希望实例的是某种类型或者性质的对象,那么需要修改为模板类的定义,这样在以后的需求改动中,就避免了不避免的麻烦。

template <typename T>
class CSingleton
{
public:
    static T* getInstance()
    {
        if (NULL == m_pInstance)
        {
            boost::unique_lock<boost::mutex> Lock(m_Mutex);
            if (NULL == m_pInstance)
            {
                //std::cout << "Thread id" << boost::this_thread::get_id() << std::endl;
                m_pInstance = new T;
            }
        }

        return m_pInstance;
    }

protected:
    CSingleton(void) {}
    virtual ~CSingleton(void) {}

private:
    static T* m_pInstance;
    static boost::mutex m_Mutex;
};

template<typename T>
T* CSingleton<T>::m_pInstance = NULL;

template<typename T>
boost::mutex CSingleton<T>::m_Mutex;

首先是模板形式,这个比较简单,读者能一眼看出其修改方式。其他改动的地方首先是if (NULL == m_pInstance) 判断为空条件写了两个,第一个是为了避免加锁解锁的耗时操作,多线程中互斥量的加锁解锁比较耗时的,所以在以后不为空的情况,都没必要进行加锁解锁,只有在第一次为空的情况,才到内部就行加锁操作。


程序代码健壮了,但是类的析构函数也是私有的,那说明如果有程序员想显示delete是不可能,那么只能增加相应的函数去删除对象。

template <typename T>
class CSingleton
{
public:
    static T* getInstance()
    {
        if (NULL == m_pInstance)
        {
            boost::unique_lock<boost::mutex> Lock(m_Mutex);
            if (NULL == m_pInstance)
            {
                //std::cout << "Thread id" << boost::this_thread::get_id() << std::endl;
                m_pInstance = new T;
                atexit(destroy);
            }
        }

        return m_pInstance;
    }

    static void destroy()
    {
        if (m_pInstance)
        {
            delete m_pInstance;
            m_pInstance = NULL;
        }
    }

protected:
    CSingleton(void) {}
    virtual ~CSingleton(void) {}

private:
    static T* volatile m_pInstance;
    static boost::mutex m_Mutex;
};

template<typename T>
T* volatile CSingleton<T>::m_pInstance = NULL;

template<typename T>
boost::mutex CSingleton<T>::m_Mutex;

上面的代码多了destroy函数来delete对象,和int atexit (void (*function) (void)); 来调用它,atexit()用来设置一个程序正常结束前调用的函数. 当程序通过调用exit()或从main 中返回时, 参数function 所指定的函数会先被调用, 然后才真正由exit()结束程序。
而C++关键volatile关键字,多线程的volatile,当两个线程都要用到某一个变量且该变量的值会被改变时,应该用 volatile 声明,该关键字的作用是防止优化编译器把变量从内存装入 CPU 寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile 的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值。详细参考C/C++ volatile让你看的更明白

参考资料:
【1】http://blog.csdn.net/likika2012/article/details/11483167
【2】http://www.jellythink.com/archives/82
【3】https://gist.github.com/daniebker/2299755
【4】http://blog.csdn.net/wwang196988/article/details/6623387

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:6676次
    • 积分:321
    • 等级:
    • 排名:千里之外
    • 原创:25篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类