关于Singleton

这东西可能每个引擎里都有吧, 不管它是宏还是模板.

用宏的人可能觉得模板编译慢, 另外不想多继承

用模板的人可以觉得宏丑陋, 不利于调试

不管哪种方式, 个人觉得这个东西总比全局变量好

这里说说几种常见的情况:

  • 最简单的
    • 这是一种偷懒的做法, 访问时自动创建
template <class T>  
class Singleton  
{  
public:  
 static T* GetInstance()  
    {  
 static T singleton;  
 return &singleton;  
    }  
};  
  • 优点: 使用方便
  • 缺点: 析构顺序无法控制, 特别是singleton之间有依赖关系时. 另外, 无法用于抽象类
  • 考虑抽象类的
    • 手动创建和销毁, 所以也能用于抽象类
template <class T>  
class Singleton  
{  
private:  
 static T *s_pSingleton;  
public:  
    Singleton()  
    {  
        assert(NULL == s_pSingleton);  
        s_pSingleton = static_cast<T*>(this);  
    }  
    ~Singleton()  
    {  
        assert(NULL != s_pSingleton);  
        s_pSingleton = NULL;  
    }  
 static T* GetInstance()  
    {   
 return s_pSingleton;  
    }  
};  
template <class T> T* Singleton<T>::s_pSingleton = NULL;  
  • 优点: 创建和销毁的顺序可以自己控制, 另外也可以用于抽象类
  • 缺点: 需要按顺序写好创建和销毁的代码, 当然也可以用Stack让这个过程自动化
  • 考虑线程安全的
    • 有时候我们想让Singleton只在一个模块内部使用, 而这个模块一般是处于自己的线程内部
    • 线程局部的好处一方面是安全, 另一方面可以针对不同的线程创建不同的singleton, 如主线程和渲染线程使用不同的IO系统
#define ThreadLocal __declspec(thread) 
template <class T>  
class Singleton  
{  
private:  
    ThreadLocal static T *s_pSingleton;  
public:  
    Singleton()  
    {  
        assert(NULL == s_pSingleton);  
        s_pSingleton = static_cast<T*>(this);  
    }  
    ~Singleton()  
    {  
        assert(NULL != s_pSingleton);  
        s_pSingleton = NULL;  
    }  
 static T* GetInstance()  
    {   
 return s_pSingleton;  
    }  
};  
template <class T> T* Singleton<T>::s_pSingleton = NULL;  
  • 考虑线程安全+DLL导出的
    • MSDN上说了, 要在DLL的环境下使用thread local的变量, 需要使用TlsAlloc系列函数
class ThreadLocalIndex  
{  
public:  
    ThreadLocalIndex()  
    {  
        m_tlsIndex = TlsAlloc();  
    }  
    ~ThreadLocalIndex()  
    {  
        TlsFree(m_tlsIndex);  
    }  
    operator DWORD() const 
    {  
 return m_tlsIndex;  
    }  
private:  
 DWORD m_tlsIndex;  
};  
template <class T>  
class Singleton  
{  
private:  
 static DWORD GetThreadLocalIndex()  
    {  
 static ThreadLocalIndex index;  
 return index;  
    };  
public:  
    Singleton()  
    {  
        assert(NULL == GetInstance());  
        TlsSetValue(GetThreadLocalIndex(), static_cast<T*>(this));  
    }  
    ~Singleton()  
    {  
        assert(NULL != GetInstance());  
        TlsSetValue(GetThreadLocalIndex(), NULL);  
    }  
 static T* GetInstance()  
    {   
 return (T*)TlsGetValue(GetThreadLocalIndex());  
    }  
};  
  • 嗯, 还没实际使用过, 有问题再说~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏desperate633

第十课 分组数据创建分组过滤分组分组和排序

** having和where的区别 **: ** where在数据分组前进行过滤,having在数据分组后进行过滤,where过滤的是行,having过滤的...

9120
来自专栏乐沙弥的世界

RMAN 提示符下执行SQL语句

       在手动恢复数据库时,有时候需要在SQL*Plus提示符以及操作系统提示符,RMAN提示符下来回切换显得有些繁琐。实际上RMAN为我们提供了命令行下...

12530
来自专栏kwcode

C# 读取指定文件夹下所有文件

#region 读取文件 //返回指定目录中的文件的名称(绝对路径) string[] files = S...

32570
来自专栏数据和云

深入剖析-关于分页语句的性能优化

分页语句是数据库开发和应用场景比较常见的需求,即按照特定的where条件进行过滤,然后在按照一个或者多个条件进行排序(如果不进行排序无法确执行时候无法返回相同的...

29190
来自专栏性能与架构

MySQL Query Cache实现原理

MySQL的Query Cache实现原理实际上并不是特别复杂,简单来说就是将客户端请求的Query语句(仅限于SELECT类型的Query)通过一定的hash...

418110
来自专栏Snova云数仓

Greenplum资源队列初识

在Greenplum的4.x版本之后,加入了资源队列的概念,其主要作用就是限制用户或者单个SQL对资源的消耗。避免出现消耗过多资源,影响其他用户或者SQL计算。...

849140
来自专栏我爱编程

Python数据库操作之pymysql模块和sqlalchemy模块

参考博客https://www.cnblogs.com/aylin/p/5770888.html

21240
来自专栏Linyb极客之路

Java面试中常问的数据库方面问题

B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接,是有序的

12930
来自专栏云计算教程系列

想熟悉PostgreSQL?这篇就够了

PostgreSQL是自由的对象-关系型数据库服务器,在灵活的BSD风格许可证下发行。它在其他开放源代码数据库系统和专有系统之外,为用户又提供了一种选择。 我们...

24920
来自专栏微信公众号:Java团长

Java面试中常问的数据库方面问题

B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接,是有序的

12530

扫码关注云+社区

领取腾讯云代金券