直接使用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(例如,如果该对象不再需要,就可以释放其占有的内存空间)。在这种情况下,你必须考虑引用计数,以避免由于过早删除造成的“虚引用”。