| 
                   | 
               
                  
                   | 
            |
On both stack and heap, objects have a lifetime that runs approximately as follows:
allocate memory for the object [on stack or heap]
initialise: i.e., set the contents of that memory to usable values
use the object
clean up: i.e., free up any other resources that might have been used by that object
de-allocate memory [from stack or heap]
Object lifetime is a fundamental concept. In some operating systems, it can be neglected, because the stack and heap are destroyed when a program terminates. On Symbian OS, programs may run for months. It is therefore important that objects be cleaned up as soon as their lifetime ends, whether they are allocated on stack or heap, and whether their lifetime ended through normal processing or through an error condition.
On the C stack, an objects lifetime, for a user of that object, might look like this:
#include "s.h"
void foo()
    {
    S s;
    sInitialize(&s, p1,p2);
    sUse(&s, p3,p4);
    sCleanup(&s);
    }
Memory for the S is allocated on entry to the
            function, and de-allocated on exit. The functions sInitialize()
            and sCleanup() have been defined as part of the API for an
            S, in s.h (in fact, C programmers are not always as
            disciplined as this, and expect the users of their objects to do their own
            initialisation, in an ad hoc way). The function sUse() represents
            a use of the S. Note that the S is passed by pointer:
            its address must be taken whenever it is used as a function parameter.
         
On the C heap, an object's lifetime might look like this:
void foo()
    {
    S* s=(S*)malloc(sizeof(S));
        // should really check this succeeded!!
    sInitialize(s, p1,p2);
    sUse(s, p3,p4);
    sCleanup(s);
    free(s);
    }
This time, a pointer is used to refer to the S: as a
            result, the syntax of passing an S is slightly more pleasant,
            because you dont have to take its address.
         
On the other hand, the allocation and de-allocation of memory is
            done using malloc(), whose syntax is extremely ugly, and
            free().
         
Mostly, the lifetime of a heap-based object would not be contained within a single function like this: it might be created from one function, used from another, and destroyed from another.
One way of looking at C++ is as a neat way to control object lifetimes.
            C++ allows functions to be associated directly with objects, which means that
            you do not need a special naming convention to indicate that a function is
            loosely associated with an object. Two special functions are the constructor
            and the destructor: the constructor is called every time the C++ system knows
            that an objects lifetime begins, and the destructor is called every
            time the C++ system knows that an objects lifetime ends. Finally, C++
            defines operator new(), which is much nicer than
            malloc(), and operator delete, which is somewhat
            nicer than free().
         
On the C++ stack, an objects lifetime looks like this:
void foo()
    {
    S s(p1,p2); // invokes constructor
    s.Use(p3,p4); // nice syntax!
    } // invokes destructor
Memory is allocated on function entry, and the constructor is invoked
            when processing reaches the declaration. The use of member functions makes the
            syntax of using everything much more pleasant: there is no need to pass a
            reference to the S, because that is done implicitly.
         
Crucially, C++ causes the destructor to be invoked when the function terminates. There is no need for the user of the class to do anything to cause this to happen all thats necessary is that the provider of the class provided a destructor.
Note, though, that in some exception conditions for
            instance, if the Use() function fails in some way
            the function may not return normally, and the destructor will therefore not be
            invoked. We will shortly discuss how Symbian OS addresses
            this.
         
On the C++ heap, object lifetime looks like this:
void foo()
    {
    S* s=new S(p1,p2); // allocate, construct - should really check
    s->Use(p3,p4);
    delete s; // destruct, de-allocate
    }
Again, the syntax is much nicer. Only one thing cannot be provided by C++: the user of a class must still remember to delete the object at the end of its lifetime.
Symbian OS idioms for object lifetime on the stack look very similar to standard C++. The control of object lifetimes on the heap is, however, very different, as shown in the following code:
void FooL()
    {
    CS* s=new (Eleave) CS; // allocate and check
    CleanupStack::PushL(s); // push, just in case
    s->ConstructL(p1,p2);    // finish constructing - might leave
    s->UseL(p3,p4); // use - might leave
    CleanupStack::PopAndDestroy();    // destruct, de-allocate
    }
This code fragment shows four vital things:
all heap-based classes have names beginning with C: they are
                  in fact derived from a single base class, CBase, which exists
                  solely to support easy cleanup
               
a cleanup stack is used to hold references to objects: if a leave occurs
                  due to out-of-memory or some other error, objects held on the cleanup stack are
                  popped from it, and destroyed. In the case of CBase* objects
                  pushed to the stack, they are destroyed by calling their C++ destructor. The
                  CBase class has a virtual destructor
                  (CBase::~CBase()) which makes this possible.
               
any function which might leave is designated by a trailing L
                  in its name. When you see a function that might leave, you must
                  always ask what would happen if it did leave, and what would
                  happen if it did not. The operating system provides all the program
                  infrastructure required to allow objects to be de-allocated even when a leave
                  occurs, but without burdening the programmer.
               
new (ELeave) is an overloaded operator new()
                  function, which will leave if it fails to allocate the required memory. It
                  never returns a null pointer.
               
Two other things are worthy of note:
since the cleanup stack itself requires memory allocation for each stack
                  frame, a push might leave. The PushL() function reflects this in
                  its name. The cleanup stack is guaranteed to have a free slot before a
                  CleanupStack::PushL(), so that the object reference will always be
                  successfully stored on the stack. If a leave occurs when allocating the next
                  stack frame, the object will be popped and destroyed as normal.
               
the C++ constructor must not leave. For objects whose
                  construction requires resource allocation or any other operation that might
                  fail, this means that construction must be separated into a C++ constructor
                  that does not leave, and another initialisation function that might leave,
                  which is conventionally called ConstructL().
               
The cleanup stack, CBase, and two-phase construction, are at
            the heart of the operating system. A very few rules govern cleanup stack
            programming, and they are relatively easy to learn. See
            Cleanup Stack Basics for more on
            this.