首先声明,我所要谈的singleton并非完美的singleton实现,包含各种智能指针和线程安全之类的,那些东西想必大家都已经看过不少了。我只是借用最基础的实现方式,谈一个大多数人可能都知道但是却没有采用的实现方案——显性初始化。这是我认为的最优方案。下面有些地方会把singleton称为单体。1.现有的两种singleton实现方法 1.1惰性初始化惰性初始化的singleton的特点有这么些:直到使用的时候才初始化,构造函数私有。代码可能如下:
1.2显性初始化显性初始化的singleton的特点有这么些:构造函数public,你需要在使用该单体之前new 一下,然后在不再需要的时候delete一下。有关的代码如下:
2.选择显性初始化方法的理由 2.1明确的构造和析构惰性初始化,他的初始化时机在第一次调用的时候,但是何时才是第一次调用,这个代码一多起来,就不是那么好把握的了。显性初始化的时机很简单,new即存在,并且可以很直观的调整构造函数的参数。在此一个疑惑的观点是多new了几次怎么办。。。我的观点是那么显性的操作,明知道是单体,明知道很关键,你还能多new几下,你就不能判断一下啊。。。。一般说来,稍微有点基础的人都不会出这种状况的,放心的new吧。看了大家写的关于惰性singleton实现的文章,都描述了一个单体析构别扭的问题,因为delete T::Singleton()就像是非法入侵,虽然不会造成什么实质性的危害,但是这本身就是一个语义范畴的悖论(我瞎说的,我连语义范畴都不知道是虾米),new和delete没有配对。 2.2继承和多态单体也会继承和多态?会哦,而且这通常是由框架本身的约束造成的,我最近的工作就碰到了。在服务器和客户端的开发项目中,通常会有base模块,即server & client base,这个模块使用了单体类A的一些接口,但是这个单体类A在服务器模块和客户端模块可是被分别实现为多少有些不同的S和C,这些实现是无法集成到base的。那么,惰性方法是如何考虑这个的呢?第一,static T& GetSingleton方法可以重载吗?我不知道,没试过。第二,假设static方法可以重载,但是base模块使用的是A::GetSingleton哦,那即使重载了也用不上吧。以此相对的,显性初始化的方法就简单多了:
2.3OGRE中使用的就是这一种最初用到OGRE的时候有些不习惯也不理解,因为他是显性初始化的,那时候我还使用惰性初始化。提OGRE并不是为了说明显性初始化好而提供什么论据,而仅仅是想说,看吧,显性初始化这种方法是有着一个优秀的库的支持的。3.其他 3.1singleton模板?就那点代码写了你会死啊,我绝不在这个地方使用模板,多写个#include和public Singleton<T>比写个函数和变量更让我痛恨。 3.2线程安全看了大家一些关于线程安全的singleton,大家都往Singleton函数加锁了。我说。。。。如果那个单体被用于线程安全的话,仅仅是Singleton函数加锁是不够的吧。况且,XP的思想是,有需求,才添加相应的功能,用不上的代码,能不加就不加。写多线程程序的情况起始还是不太多的吧。 3.3singleton和全局变量有什么区别?(小白创可贴)其实没啥区别的,就是一个命名协议的问题(我是完全这么认为的)。如果全局变量的命名协议能规定为 g_classname,比如class CBoxManager; 相应的全局变量命名为 g_pCBoxManager的话,不用singleton也可以哦。不然的话,每个单体变量的命名都没个准,这在team work中是一个让人起小疙瘩的事情。PS:加入代码的DLG里居然没有C/C++选项,这里可是cpp blog啊^O^~