Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 9
Текст из файла (страница 9)
// Free up some memory and try again...break;...default:User::Leave(err);break;}}Otherwise it can just call the function directly and allow a higher-leveltrap handler to handle all the leave codes:CFileObject* fileObject = LeavingExampleL();As an alternative to leaving on all errors, the function to instantiatea CFileObject could TRAP the call to CFileObject::NewL() andinstead return an error for all failures:TInt Example(CFileObject*& aFileObject){RFile file;TInt error = file.Open(...);if (error == KErrNone){TRAP(error, aFileObject = CThing::NewL(file));}return error;}Again, if the calling code can handle some errors, it can switch on thereturn code; otherwise, it can call the function inside User::LeaveIfError() to pass all failures up to a TRAP harness in higher-level code.CFileObject* fileObject = NULL;User::LeaveIfError(Example(fileObject));Which of the two implementations is preferable? Well, the leaving version is smaller and simpler and, as Martin Fowler discussesin Refactoring: Improving the Design of Existing Code (see Bibliography for further details), the use of exceptions clearly separates normal processing from error processing.
Furthermore, the use of thealternative, error-returning function always incurs the overhead of a26LEAVES: SYMBIAN OS EXCEPTIONSTRAP, even if none of the callers can handle errors and they all callUser::LeaveIfError() as shown in the previous code sample.However, if you know who all your callers are (for example, if thefunction is internal to your component) and you know that the callerswill all TRAP the call, it may be worthwhile implementing the versionthat returns an error. This limits the use of a TRAP to one place inthe code.Use of TRAP is an expensive way of managing a leave in termsof executable size and execution speed.
You should attempt tominimize the number of TRAPs you use in your code wherepossible. However, every program must have at least one TRAP tocatch any leaves that occur.2.6 LeaveScanLeaveScan is a useful tool which you should run regularly against yoursource code. It checks that all functions which have the potential to leaveare named according to the Symbian OS convention, with a trailing L.LeaveScan can be used on your source to indicate areas of code whereyou may have forgotten to use the convention.
By revealing where leavesmay occur but are not acknowledged by the function name, it highlightspotential bugs and gives you an opportunity to fix the problem and ensurethat your code handles any leaves correctly.LeaveScan works by examining each line of source code and checkingthat functions which do not terminate in L cannot leave. However, thereare a few functions (more accurately, operators) in Symbian OS thatmay leave but cannot have an L suffix (such as operator<< andoperator>> for RWriteStream and RReadStream respectively).The naming convention cannot be applied appropriately to operatorsand, unfortunately, LeaveScan does not have the sophisticated logicneeded to recognize operators that may leave.
When you use operatorsthat you know have the potential to leave, you’ll have to remember tocheck this code by sight yourself.LeaveScan also checks functions which do have a trailing L to seeif they really can leave. If functions are encountered which do notleave, LeaveScan raises a warning.
However, this scenario can be perfectly valid, for example, when implementing an abstract function suchas CActive::RunL(), some implementations may leave but othersmay not.SUMMARY27LeaveScan will highlight functions which may leave but are incorrectly named without a suffixed ”L”. The potential to leave occurswhen a function:• calls other functions which themselves leave (and thus havefunction names ending in L) but does not surround the functioncall with a TRAP harness• calls a system function which initiates a leave, such asUser::LeaveIfError() or User::Leave()• allocates an object on the heap using the Symbian OS overloadof operator new.2.7 SummaryThis chapter discussed leaves, which are the lightweight equivalent ofC++ exceptions on Symbian OS.
A leave is used to propagate an errorwhich occurs because of exceptional conditions (such as being out ofmemory or disk space) to higher-level code which can handle it. A Symbian OS leave is equivalent to a C++ throw and a TRAP harness is usedto catch the leave. In fact, a TRAP harness is effectively a combination oftry and catch.Having compared leaves and TRAPs with standard C++, it’s worthmaking a comparison with the standard library too. TRAP and leaveare analogous to the setjmp() and longjmp() methods, respectively – setjmp() stores information about the location to be ”jumpedto” in a jump buffer, which is used by longjmp() to direct the code tojump to that point.On Symbian OS, if a function can leave, that is, fail under exceptionalconditions, it indicates this by suffixing its function name with L.
Of allthe Symbian OS naming conventions, this is one you should comply withbecause, if you don’t, it’s hard to know whether you can call a functionwithout potentially orphaning any local heap-based variables. You cancheck that you have adhered to the naming convention by running theLeaveScan tool over your source code.A function can leave if it calls one of the system functions whichcause a leave (such as User::Leave()), calls another leaving function(such as NewL()) or allocates memory using the Symbian OS leavingoverload of operator new. Some functions should not leave, namelyconstructors (I’ll discuss the reasons behind this in detail in Chapter 4,28LEAVES: SYMBIAN OS EXCEPTIONSand explain how two-phase construction can be used to prevent it)and destructors, which could potentially leak memory by leaving beforecompleting object cleanup.This chapter described best practice for writing and calling leavingcode, particularly when a function may have a return value for initializedpointer data.
It also discussed the best use of the TRAP and TRAPDmacros, which can have a significant overhead in terms of code size andruntime speed.The next chapter discusses the use of the cleanup stack to protectheap-based local variables against orphaning in the event of a leave.3The Cleanup StackLife is pleasant. Death is peaceful.
It’s the transition that’s troublesomeJimi HendrixThis chapter discusses a fundamental part of Symbian OS, the cleanupstack. Symbian OS is designed to perform well with limited memory,and part of that design must inevitably consider memory managementwhen errors occur. The cleanup stack manages memory which wouldotherwise be ”orphaned” (leaked) in the event of a leave.But what, exactly, is ”orphaning”? In the previous chapter, I describedwhy Symbian OS doesn’t use standard C++ exceptions, but insteadhandles exceptional conditions using ”leaves”. Code that can leave is, atsome level, surrounded by a TRAP, or TRAPD, harness.
If a leave occurs,control is transferred directly to the statement following the harness. Ineffect, the TRAP is equivalent to a setjmp and the leave to a longjmp.The stack memory is freed as the stack unwinds, but otherwise thestack frame is abandoned and no object destructors are called (whichis unlike a standard C++ exception). This means that the destructors ofany local variables or arguments passed by value, or objects created asmember variables of either of these, will not be called. Some objectsare ”leave-safe” – they do not need destructors and contain only datawhich can be destroyed as stack memory is freed by the leave.
Thisdata may consist of the basic, built-in types or other objects whichcontain such types. In Symbian OS these are called T classes (T for”type”, described in detail in Chapter 1), the characteristic of which isthat they may safely be created on the stack in functions where codemay leave.If a local variable is a pointer to an object on the heap, when a leaveoccurs the pointer is destroyed without freeing that heap memory, whichbecomes unrecoverable, causing a memory leak.
The memory is said tobe orphaned. This means that C class objects, which are always createdon the heap, as described in Chapter 1, are not leave-safe. Unless theyare otherwise accessible for safe destruction (for example, as membervariables of an object which is destroyed regardless of the leave), the30THE CLEANUP STACKmemory they occupy on the heap and any resources they own areorphaned by a leave. R class objects are generally not leave-safe either,since the resources they own must be freed in the event of a leave (througha call to the appropriate Close() or Release() type function). If thiscall cannot made by an object accessible after the leave, the resourceis orphaned.Consider the following code, which creates an object of a C class(CClanger) on the heap, referenced only by an automatic variable,clanger.