现在的位置: 首页 > 综合 > 正文

Symbian DLL中可写静态数据问题 (二)DLL中实现单例模式

2018年01月11日 ⁄ 综合 ⁄ 共 2340字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.