This document describes the requirements for cleanup after a function leaves.
When a function leaves, it transfers control directly to the statement
following the TRAP
(or TRAPD
) macro under
which it was invoked. This is carried out by setting the stack pointer to
the context of the original TRAP
macro, and jumping to the
desired program location. Therefore,
any objects created as automatic variables, passed by value as arguments, or created as member variables of other objects so created, will be orphaned: their destructor will not be called, and any resources they claim except for storage space on the stack, cannot be recovered.
This key aspect of Symbian platform exceptions has far-reaching implications:
There should be a clear distinction between objects which can be safely orphaned, and those which cannot.
This is embodied in the naming convention for types. All types
beginning with T
can be safely orphaned, including, for instance, TInt
, TPoint
, TPtr
and many others. Such objects can be freely allocated on the stack.
The
basic requirement for T
objects is that all their data is
contained internally. Pointers, handles and references to data owned by the T
object
are not allowed (although such references to data owned by other objects is
allowed).
C
objects must never be orphaned: they should
never be allocated on the stack.
R
objects may contain
handles to external resources, but are generally designed so that the R object
can be copied without copying its resources. Copied R
objects
may therefore be allocated on the stack: the stack-allocated copies may safely
be orphaned, provided the resources are safely accessible by some other means.
Objects which cannot be safely orphaned must, if allocated inside the trap harness, be accessible somehow so they can be cleaned up.
The cleanup stack is the Symbian platform mechanism for handling this last problem.
The problem for heap-allocated resources
is shown below. If the call to DoSomethingL()
leaves, the CExample
object
would be orphaned on the heap: the memory used for it could
not have been recovered until the program terminates.
void doExampleL() { // An T-type object: can be declared on the stack TBuf<10> buf; // A C-type object: must be allocated on the heap // Allocate and leave if can not CExample* myExample = new (ELeave) CExample; // do something that cannot leave: no protection needed myExample->iInt = 5; // PROBLEM: do something that can leave myExample->DoSomethingL(); // delete delete myExample; }