This page was last modified 20:31, 14 October 2007.
Simple Reference Counting Singleton
From Forum Nokia Wiki
Contents |
What is a singleton?
Singleton is a design-pattern originally described by the Gang of Four (GoF). The basic idea is to ensure that only one instance of the class will ever exist. The class will typically have a static function that can be used to get the instance and the class will internally keep track of itself and either create the single instance or return a pointer to it.
Why won't the typical C++ implementation work in Symbian?
The simplest singleton example shown in most C++ books uses a static pointer to store the instance. A static pointer will continue to exist for the duration of the process so it is a very convenient way to implement a singleton. This however doesn't work in a Symbian DLL because the static pointer is writable static data (WSD) and it is not allowed in Symbian DLLs. (It can be enabled with EPOCALLOWDLLDATA but it is not recommended).
The CCoeStatic solution
In application code that has access to CCoeEnv the simplest way to implement a singleton is to derive the class from CCoeStatic.
Example of this can be found hereMore generic solution using TLS
If the code needs to work also in non-UI processes, the easiest way is to use TLS. The approach doesn't differ much from the C++ book example except that the static pointer is replaced with TLS.
This example will create a reference counted singleton that manages its own lifetime. The users are only required to call Release() on it when they no longer use it.
RefCountingSingleton.h
#ifndef CREFCOUNTINGSINGLETON_H #define CREFCOUNTINGSINGLETON_H #include <e32base.h> /** * Simple reference counting singleton example */ class CRefCountingSingleton : public CBase { public: /** * Returns the singleton instance. * @return Instance of class CRefCountingSingleton */ static CRefCountingSingleton* InstanceL(); /** * Returns the singleton instance. Pushes it on the cleanup stack * @return Instance of class CRefCountingSingleton */ static CRefCountingSingleton* InstanceLC(); /** * Releases the singleton instance. */ void Release(); private: CRefCountingSingleton(); /** * Private destructor so users can't directly delete this instance. * They must call Release() */ virtual ~CRefCountingSingleton(); void ConstructL(); private: // data /** * Amount of references to the singleton instance. * Instance will be deleted when count reaches zero. */ TInt iReferenceCount; }; #endif // CREFCOUNTINGSINGLETON_H
RefCountingSingleton.cpp
#include "simplesingleton.h" // --------------------------------------------------------------------------- // Returns the singleton instance. // --------------------------------------------------------------------------- // CRefCountingSingleton* CRefCountingSingleton::InstanceL() { CRefCountingSingleton* self = NULL; TAny* tlsPtr = Dll::Tls(); if ( tlsPtr == NULL ) { self = new( ELeave ) CRefCountingSingleton; CleanupStack::PushL( self ); self->ConstructL(); User::LeaveIfError( Dll::SetTls( self ) ); CleanupStack::Pop( self ); } else { self = static_cast<CRefCountingSingleton*>( tlsPtr ); ++self->iReferenceCount; } return self; } // --------------------------------------------------------------------------- // Returns the singleton instance. Pushes it in the cleanup stack // --------------------------------------------------------------------------- // CRefCountingSingleton* CRefCountingSingleton::InstanceLC() { CRefCountingSingleton* self = InstanceL(); CleanupReleasePushL( *self ); return self; } // --------------------------------------------------------------------------- // Releases the singleton instance. // --------------------------------------------------------------------------- // void CRefCountingSingleton::Release() { TAny* tlsPtr = Dll::Tls(); __ASSERT_DEBUG( tlsPtr != NULL, User::Panic( _L( "CRefCountingSingleton" ), KErrNotFound ) ); CRefCountingSingleton* self = static_cast<CRefCountingSingleton*>( tlsPtr ); if ( --self->iReferenceCount == 0 ) { Dll::FreeTls(); delete self; } } // --------------------------------------------------------------------------- // // --------------------------------------------------------------------------- // CRefCountingSingleton::CRefCountingSingleton() : iReferenceCount( 1 ) { } // --------------------------------------------------------------------------- // // --------------------------------------------------------------------------- // void CRefCountingSingleton::ConstructL() { // Perform any necessary initialization } // --------------------------------------------------------------------------- // Destructor // --------------------------------------------------------------------------- // CRefCountingSingleton::~CRefCountingSingleton() { }
Note
The above code will work only work in a DLL because it accesses TLS through the Dll class that is provided for every DLL. See here for instructions on how to access TLS from an EXE project.
| Related Discussions | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Firmware bug or code bug displaying list on 3650 | blackjack75 | Mobile Java General | 2 | 2003-09-24 19:52 |
| how do i know the message in a sms has reach the maximum limit? | yuenfatt | Symbian Networking & Messaging | 3 | 2007-09-13 11:30 |
| Replace a placeholder in _LIT with a string? | kaiten-sushi | General Symbian C++ | 7 | 2007-01-29 15:23 |
| 如何获得当前激活app的底部按键提示文字? | allyfeng | Symbian | 13 | 2005-09-30 02:56 |
| Can I Make or Answer a call using J2ME ? | Bobby_Stokes | Mobile Java Tools & SDKs | 1 | 2004-02-13 20:08 |
