直接使用WSD的方式就不介绍了,和普通的单例实现一样。
使用TLS的Singleton的典型实现。
class CSingleton : public CBase { public: // 访问/创建Singleton实例 IMPORT_C static CSingleton& InstanceL(); private: // 为了表示清楚,这些函数没有实现 CSingleton(); ~CSingleton(); void ConstructL(); }; EXPORT_C /*static*/ CSingleton& CSingleton::InstanceL() { CSingleton* singleton = static_cast<CSingleton*>(Dll::Tls()); if (!singleton) // 不存在Singleton实例。创建一个。 { singleton = new(ELeave) CSingleton(); CleanupStack::PushL(singleton); singleton->ConstructL(); User::LeaveIfError( Dll::SetTls(static_cast<TAny*>(singleton)) ); CleanupStack::Pop(singleton); } return (*singleton); }在Symbian OS v9之前,应用程序都是DLL,都无法使用WSD。Singleton基于TLS的实现被认为是在经典模式下使用WSD的一种直接的替代方式。为了保证该过程的简易型,Symbian OS为应用程序开发者提供额外的机制,如下:
CCoeStatic实现单例
该方法很直接只需要从CCoeStatic继承你的Singleton类。例如:
class CAppSingleton : public CCoeStatic { public: static CAppSingleton& InstanceL(); static CAppSingleton& InstanceL(CCoeEnv* aCoeEnv); private: CAppSingleton(); ~CAppSingleton(); };该类的实现必须将自身与UID关联起来,以允许Singleton实例“注册”到应用程序框架中(类CCoeEnv)。当Singleton对象实例化后,CCoeStatic基类构造函数将该对象添加至CCoeEnv保存的Singleton列表中。在内部,CCoeEnv使用TLS来保存每个注册Singleton对象的指针(使用包含指向CCoeStatic派生对象指针的双向链表)。因此,CAppSingleton实现如下:
const TUid KUidMySingleton = {0x10204232}; // "register"singleton CAppSingleton::CAppSingleton() : CCoeStatic(KUidMySingleton, CCoeStatic::EThread) {} // 使用CCoeStatic::Static()访问Singleton CAppSingleton& CAppSingleton::InstanceL() { CAppSingleton* singleton = static_cast<CAppSingleton*>(CCoeStatic::Static(KUidMySingleton)); if (!singleton) {// 忽略二阶段构造 singleton = new(ELeave) CAppSingleton(); } return (*singleton); } // 使用CCoeStatic::FindStatic()访问Singleton CAppSingleton& CAppSingleton::InstanceL(CCoeEnv* aCoeEnv) { CAppSingleton* singleton = static_cast<CAppSingleton*> (aCoeEnv->FindStatic(KUidMySingleton)); if (!singleton) {// 忽略二阶段构造 singleton = new(ELeave) CAppSingleton(); } return (*singleton); }
// 来自coemain.h static CCoeStatic* Static(TUid aUid); CCoeStatic* FindStatic(TUid aUid);这些函数遍历双向链表,将CCoeStatic派生对象和应用程序UID进行匹配。CCoeStatic只能被运行于应用程序框架内部的代码使用,例如控件环境(CONE)。
Singleton清理
本文中讨论的所有实现都声明Singleton类的析构函数为私有函数,并且返回的是Singleton引用而不是指针。这是因为,如果析构函数是 公共的,并且返回的是Singleton实例的指针,那么它可能被其它调用者无意销毁,使得Instance()函数处理已经删除示例的“虚引用”。给出 的实现防止了这种情况的发生,并且让Singleton类负责Singleton实例的创建、所有权,以及最终的清理。
清理的通常方法是使用标准C程序库提供的atexit函数与清理函数进行注册,这些清理函数在进程终结的时候被显式调用。清理函数可以是Singleton类的成员函数,简单地删除Singleton实例。更多详情请参见。
然而,你也许希望在进程终结之前销毁Singleton(例如,如果该对象不再需要,就可以释放其占有的内存空间)。在这种情况下,你必须考虑引用计数,以避免由于过早删除造成的“虚引用”。