Cleanup support for ResetAndDestroy()
18 Oct 2004 - 20:54

After some looking into the matter I've decided that either there is no way to do this using the standard Symbian API or I that I am too blind to find one, I wrote one myself.

The point is to make a dynamic array's ResetAndDestroy() method being called for an array pushed onto the cleanup stack upon a leave or an explicit call to PopAndDestroy(). While this functionality might be rarely necessary or desired, there are cases where allocating an dynamic array on the heap is the most elegant solution. This approach requires efficient and clean cleanup support, and here's how I've addressed the problem.

In practice, here's how it's used (code simplified and lacking error checking etc.):

SomeCode.cpp:

#include "CleanupResetAndDestroy.h"
..

RPointerArray<CMyType>* list = new RPointerArray<CMyType>( 1 );
CleanupResetAndDestroyPushL( list );

// add stuff to list
// use list

CleanupStack::PopAndDestroy(); // list

What happens in PopAndDestroy():

  1. . list->ResetAndDestroy();
  2. . delete list;

The following code is from my soon-to-be-released project Nova3D, written under the LGPL licence.

CleanupResetAndDestroy.h:

/*
*  $Id: CleanupResetAndDestroy.h,v 1.1 2004/10/16 11:02:37 matti Exp $
*
*  Nova 3D Engine - A real-time 3D graphics framework for Symbian environments
*  Copyright (C) 2001-2004 Matti Dahlbom
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Contact: Matti Dahlbom <matti at 777-team dot org>
*/

#ifndef __CLEANUPRESETANDDESTROY_H
#define __CLEANUPRESETANDDESTROY_H

#include <e32base.h>

template <class T> void CleanupResetAndDestroyPushL( T* aObj );

/**
* Utility template class to perform thorough cleanup for classes like
* RPointerArray; upon cleanup, ResetAndDestroy() is called for the object
* after which the object itself is deleted.
*
* @author Matti Dahlbom
* @version $Name:  $, $Revision: 1.1 $
*/
template <class T> class TCleanupResetAndDestroy : public CBase
{
   private: // Constructors and desctructor
       inline TCleanupResetAndDestroy( T* aObj );
       inline ~TCleanupResetAndDestroy();

   private: // Data
       T* iObj;

#ifdef __WINS__
       // MSVC++ way
       friend void CleanupResetAndDestroyPushL( T* aObj );
#else
       // gcc way
       friend void CleanupResetAndDestroyPushL<>( T* aObj );
#endif
};

//=================================================
// template class method implementations
//=================================================

template <class T> TCleanupResetAndDestroy<T>::TCleanupResetAndDestroy( T* aObj )
   : iObj( aObj )
{
}

template <class T> TCleanupResetAndDestroy<T>::~TCleanupResetAndDestroy()
{
   iObj->ResetAndDestroy();
   delete iObj;
}

/**
* Pushes an object on cleanup stack. Object's ResetAndDestroy() will be called
* upon cleanup.
*/
template <class T> inline void CleanupResetAndDestroyPushL( T* aObj )
{
   TCleanupResetAndDestroy<T>* item = new (ELeave) TCleanupResetAndDestroy<T>( aObj );
   CleanupStack::PushL( item );
}

#endif

Tutorial posted October 18th, 2004 by mdahlbom

Submitted by Anonymous on Tue, 2004-10-19 08:24.

Actually there is Symbian API support for this kind of behaviour.

Implement a cleanup method taking a TAny* parameter like void CleanupArray(TAny* aObj); and inside that method cast the aObj to correct array type and then call ResetAndDestroy().

To use the cleanup method push a TCleanupItem to the cleanup stack: RPointerArray<CMyType>* list = new RPointerArray<CMyType>( 1 ); CleanupStack::PushL(TCleanupItem(CleanupArray, list)); //... CleanupStack::PopAndDestroy();


Submitted by tOtE (not verified) on Wed, 2004-10-27 20:02.

That's a great solution, I like it! To support this feature, you either have to use cleanup items or TRAP the first leave. And I agree that TRAPping is much more expensive and, on the other hand, using TCleanupItem is much nicer. Cool.

Submitted by Anonymous on Tue, 2005-10-04 10:33.

Actually there is an entire implementation of this already provided in Symbian 7.0s in the mmf\common\mmfcontrollerpluginresolver.h class

No I don't kno why it was put there and I know the some of the guys in Symbian that wrote the MMF module!


Submitted by Artem (not verified) on Sat, 2006-06-17 14:28.


Submitted by Anonymous on Thu, 2004-10-21 10:46.

There is a subtle flaw in this, in that if the first line of the CleanupResetAndDestroyPushL method leaves then the array does not get cleaned up.

All the standard clean up stack functions guarantee that they take ownership of the object passed in. To do this they make sure that there is always at least one spare slot on the clean up stack. If a call to CleanupStack::PushL or CleanupClosePushL (or others) uses the last available slot, the stack will allocate more memory, which could cause a leave, which is why all the xxxPushL functions can leave. If a leave occurs, the object that was pushed on is destroyed along with the rest of the clean up items on the stack. Doing any kind of leaving operation in a CleanupResetAndDestroyPushL style function before the item is on the clean up stack is unsafe.



copyright 2003-2009 NewLC SARL