Wiley.Symbian.OS.C.plus.plus.for.Mobile.Phones.Aug.2007 (779890), страница 16
Текст из файла (страница 16)
Objects are created, have a finitelifetime, and are then destroyed.We’ll look first at the basics of object creation and destruction. In someways this may give a misleading picture; the full picture will only emergeonce we’ve looked at error handling and cleanup. This is because objectcreation, object destruction, error handling and cleanup are all intimatelytied together with the aim of ensuring that:• objects, once created, are always destroyed when no longer needed• objects are never left half-created, that is with memory occupied orunavailable, if an error occurs during the creation process.There are two places in Symbian OS that objects can be created: theheap and the program stack.The Heap (Dynamic Objects)All threads have an associated heap, termed the default heap, from whichmemory can be allocated at run time.
This is where you put large objectsand objects that can only be built at run time, including (but not limitedto) dynamic variable-length strings. This is also where you put objectswhose lifetimes don’t coincide with the function that creates them; typically such objects become data members of the parent or owning object,with the relationship expressed as a pointer from the owning object tothe owned object.Memory is allocated from the thread’s default heap, as and whenrequired, using the C++ operator new or, very rarely, using user libraryfunctions such as User::Alloc().
If there is insufficient free memory,then an allocation attempt fails with an out-of-memory error.In Symbian OS, classes that are intended to be instantiated on theheap are nearly always derived from the CBase class (see Section 4.2).All CBase-derived classes must be placed on the heap, but not all heapobjects are necessarily CBase-derived.OBJECT CREATION AND DESTRUCTION63Creating objectsThe following code fragment shows a simple way of creating a heap-basedobject.class CMyClass : public CBase{public:CMyClass();∼CMyClass();void Foo();private:TIntiNumber;TBuf<32> iBuffer;}CMyClass* myPtr = new CMyClass;if (myPtr){myPtr->Foo(); // can safely access member data & functions}delete myPtr;If there is insufficient memory to allocate the CMyClass object,then myPtr is NULL.
If allocation succeeds, myPtr points to the newCMyClass object and the data members iNumber and iBuffer areguaranteed to be binary zeroes.The delete operator causes the object’s destructor to be called beforethe memory for the object itself is released back to the heap.There’s one very important variation on this:CMyClass* myPtr = new (ELeave) CMyClass;myPtr->Foo(); // can safely access member data & functionsdelete myPtr;The main difference here is that we have specified ELeave as part ofthe new operation. Instead of returning a NULL value when there isn’tenough memory to create the CMyClass object, the operation leaves.As discussed in earlier chapters, the Symbian OS Leave corresponds toa standard C++ throw.
Leaving is explained in detail in Section 4.3, butthink of it for the moment as an operation where the function returnsimmediately.If the new operation doesn’t leave, then memory allocation for the newobject has succeeded, the object has been created, and program controlflows to the next C++ instruction, myPtr->Foo(). There is no need tocheck the value of myPtr; the fact that the new operation has returnedmeans that myPtr will have a sensible value.Conversely, if the new operation leaves, the next line (which wouldotherwise be unsafe) will not be executed.64OBJECTS – MEMORY MANAGEMENT, CLEANUP AND ERROR HANDLINGOwnership of objectsIn a typical object-oriented system such as Symbian OS, where objects arecreated dynamically, the concept of ownership is important.
All objectsneed to be unambiguously owned so that it is clear who has responsibilityfor destroying them.It is good practice to determine who owns each object at the designstage. Then it is, usually, just a matter of ensuring that the owner(typically a class) contains the implementation for both the creation andthe destruction of the object.Simply having a pointer to an object does not automatically implyownership (that is, a ‘has-a’ relationship). Occasionally, a pointer to anobject exists merely in order to facilitate access to its contents (that is, a‘uses-a’ relationship).
Symbian OS tries to address the possible ambiguityby wrapping non-owned objects into R classes (see Section 4.2).The basic rules to observe are as detailed below:• Use a destructor to destroy objects that you own. Never assumeautomatic cleanup for anything.• Beware of any transfers in the ownership of objects. The owner of theobject at the time of its destruction is not necessarily the same as atthe time of its creation.• Do not attempt to destroy objects that you do not own. In the case ofa ‘uses-a’ relationship rather than a ‘has-a’ relationship, it is unsafe todelete the pointed-to object – the actual owner of the object will laterattempt to delete it, with potentially disastrous results.
This is knownas double deletion.• Don’t forget about objects – even by accident. Don’t allocate objectstwice. It sounds obvious, but allocating an object a second time andputting the address into the same pointer variable into which youput the address of the first allocated object means that you lose allknowledge of that first object. There is no way that a class destructor orany other part of the C++ system can find this object, and it representsa memory leak.Deleting objectsAs we’ve seen, deleting an object is simply a matter of using the deleteoperator on a pointer to the object to be deleted.
If a pointer is alreadyzero, then calling delete on it is harmless.However, you must be aware that delete does not set the pointeritself to zero. While this does not matter if you are deleting an object fromwithin a destructor, it is very important if the deletion occurs anywhereelse. Double deletion doesn’t always cause an immediate crash, andOBJECT CREATION AND DESTRUCTION65sometimes it leaves side effects that only surface a long time after the realproblem occurred.
As a result, double deletions are very hard to debug.On the other hand, double deletions are easy to avoid: just follow thislittle discipline:C++ delete does not set the pointer to zero. If you delete any memberobject from outside its class’s destructor, you must set the memberpointer to NULL.The Program Stack (Automatic Objects)The stack is used to hold the C++ automatic variables for each function.It is suitable for fixed-size objects whose lifetimes coincide with thefunction that creates them.In Symbian OS, the stack is a limited resource. A thread’s stack cannotgrow after a thread has been launched; the thread is panicked (terminatedabruptly) if it overflows its stack. This means that the stack should only beused for small data items, for example strings of a few tens of characters.A good rule of thumb is to put anything larger than a file name ontothe heap.
However, it is quite acceptable to put pointers (and references)into the stack, even pointers to very large objects. This is because whatactually goes into the stack is the memory address of the object, ratherthan the object itself.You can control the stack size in an executable program, through theuse of the epocstacksize keyword in the MMP file used to createthe EXE. You can also control the stack size when you launch a threadexplicitly from your program. However, creating large stacks eats intovaluable resources, and is therefore considered bad practice.Only Symbian OS T-class objects, as defined in Section 4.2, can safelybe put onto the program stack.
These include built-in types and classesthat don’t need a destructor because they own no external data. Thismeans that they can be safely discarded, without the need for any kindof cleanup, simply by exiting from the function in which the automaticvariable was declared.In the following example function, a TInt and a TBufC<16> type arecreated as automatic variables, used in the body of the function, and thensimply discarded, without any kind of cleanup, when the function exits.void CMyClass::Foo(){TInt myInteger;TBufC<16> buffer;...// main body of the function} // variables are safely discarded on exit from the function.66OBJECTS – MEMORY MANAGEMENT, CLEANUP AND ERROR HANDLING4.2 Class Categories in Symbian OSChapter 3 gave a brief overview of the Symbian OS class naming conventions. The class categories are based on:• the likely size of a class object• its likely location in memory (heap or stack)• whether the object is going to own other objects or be owned bythem.In this section we present the characteristics of each class category indetail.T and C ClassesThe naming convention for classes has been chosen to indicate their maincleanup properties.
This section presents the cleanup-related propertiesof C and T classes, which are quite similar.Classes with names beginning with C are derived from CBase andallocated on the heap. They must therefore be cleaned up when they areno longer needed. Most C classes have a destructor.A C class is typically referred to by a pointer stored in a membervariable of some class that owns it, a member variable of a class that usesit, or an automatic variable.If a C class is referred to only by a single automatic, in a function thatmight leave, then a copy of the pointer should be kept somewhere so thatit can be properly deallocated if an error occurs. Symbian OS uses thecleanup stack for this purpose (see Section 4.4).CBase offers two things to any C class:• zero initialization, so that all member pointers and handles are initiallyzero, which is cleanup-safe• a virtual destructor, so that CBase-derived objects can be properlydestroyed from the cleanup stack.By contrast, classes with names beginning with T are classes, or built-intypes, that don’t need a destructor because they own no data external tothemselves.
Examples of T types are:• any built-in type (defined using typedef), for example TUint for anunsigned integer• any enumerated type, for example TAmPm, which indicates whethera formatted time-of-day is am or pm; all enumerations begin with T,while enumerated constants, such as EAm and EPm, begin with ECLASS CATEGORIES IN SYMBIAN OS67• class types that do not need a destructor, for example TBuf<40> (abuffer for a maximum of 40 characters) and TPtrC (a pointer to astring of any number of characters).