Every object allocated on the heap should be protected by pushing its pointer to the cleanup stack via CleanupStack::PushL. Kernel resources used by the R-objects like RPointerArray are protected via CleanupClosePushL.
Sometimes you’d like or have to protect all the RPointerArray content without pushing all the individual items to the cleanup stack. There are custom solutions for this purpose, but there is also a built-in facility – CleanupResetAndDestroyPushL. It is not well known and not widely used only because it is defined in a quite an unusual place - \epoc32\include\mmf\common\mmfcontrollerpluginresolver.h
It is used as simply as:
#include
…
RPointerArray array;
CleanupResetAndDestroyPushL( array );
HBufC* string1 = HBufC::NewLC( 50 );
*string1 = _L( "string 1" );
array.AppendL( string1 );
CleanupStack::Pop( string1 );
HBufC* string2 = HBufC::NewLC( 50 );
*string2 = _L( "string 2" );
array.AppendL( string2 );
CleanupStack::Pop( string2 );
// At this point only the array is on the cleanup stack
// Destructors of the stored objects are called
CleanupStack::PopAndDestroy( &array );
In case of leave, ResetAndDestroy method is called on the RPointerArray, all the stored objects are deleted and the array can be disposed, no need for calling Close().
There is a minor restriction with the usage of the CleanupResetAndDestroyPushL. If you store in your array objects that implement some M-class interfaces and you store them by their M-class pointers (for example, if you got the pointer from the system and you don’t know the real class), make sure that the pushed M-class interface has a public virtual destructor defined.
Pushing and pop and destroying a CEmployee as MPerson will work:
/**
* An interface class *with* a virtual destructor
**/
class MPerson
{
public:
virtual TInt Age() const = 0;
virtual TDesC& Name() const = 0;
virtual ~MPerson() {};
};
/**
* A C-based class that implements the MPerson
*/
class CEmployee : public CBase, public MPerson
{
public:
static CEmployee* NewL( TInt aAge, const TDesC& aName, TInt aSalary );
virtual ~CEmployee();
// From MPerson
virtual TInt Age() const;
…
};
If you push CSquare as MImage, PopAndDestroy would result in USER 42 panic:
/**
* An interface class without a virtual destructor
*/
class MImage
{
// Oups, somebody forgot to declare
// the public virtual destructor
//public:
// virtual ~MImage() {};
public:
TInt iColor;
};
/**
* A C-based class, that implements the MImage
*/
class CSquare : public CBase, public MImage
{
public:
TInt iSize;
};
The program attached demonstrates all three cases: simple, correct pushing of the M-Class and incorrect pushing of the M-Class. The example is a universal GUI application, that can be run both on S60 2nd edition and on S60 3rd edition.
How do you like the example? Are examples on such a small features useful for you or do you find bigger application like examples more interesting?
| Attachment | Size |
|---|---|
| PopAndDestroyPusher.zip | 27.39 KB |