Programming mobile devices Part II Programming Symbian devices
Programming mobile devices Part II Programming Symbian devices with Symbian C++ Basic Symbian programming
Content of this part • • • Basic Data Types Classes Error handling Cleanup Panics Libraries
Basic Data Types • TInt, TUint integer, natural word length • TInt 8, TInt 16, TInt 32 integers of 8 b, 16 b. . . • TUint 8, TUint 16, TUint 32 unsigned integers of 8 b, 16 b and 32 b • TInt 64 64 bit integer with operators(+, -, . . . ) • TText 8, TText 16, TText characters • TChar A character class with several methods for manipulating
Basic Data Types • TBool ETrue / EFalse • TReal 32, TReal 64, TReal floating point numbers (TReal 64 and TReal map to double) • TAny like void, used in situations other than return values of functions
Classes • 4 main gategories with agreed prefixes • T for data type classes (e. g. TInt) • C for Heap allocated classes (these inherit from CBase class) • R for Resource classes (which reserve resources) • M for Interface classes
Data Type Classes • Encapsulate basic data types, such as TInt and int • Usually have methods for manipulating the data • e. g. TChar. lowe. Case() • Comparison usually implemented • Used instead of basic data types
Heap Classes • All inherit from the CBase class • Instantiated on the heap (using the new operation) • CBase has a virtual destructor (A heap class hence has to implement it) • zero initialization to all members
Resource classes • • • Control resources owned by someone else e. g. client in a client/server communication usually allocated on the stack for example: RFile, RSocket, RThread Pointers to a resource, deleting the class does not usually delete the resource • A resource has a reference count (How many pointers point to it)
Interface classes • • • M for Mixin Abstract classes that define interfaces No member variables Methods usually pure virtual Note: Even though multiple inheritance is possible in C++, in Symbian programminig it is usually used only through interfaces. • Basically: use interfaces as in Java
Errors and Exceptions • Handling errors and exceptions is utterly important in mobile phone apps. • Sources of exceptions are vast; out of memory, incoming call, empty battery. . . • Users have high expectations of robustness of the phones and the software on them.
Return Codes • Function's return value tells the result of excecution • KErr. None -success • Others include an error code that tells what went wrong, e. g. KErr. No. Memory • Used extensively in the APIs • Still, not the best possible error handling mechanism. why ?
Leave/Trap • Corresponding to Javas try-catch and C++ throw-catch, Symbian has a mechanism called leave-trap • leave is like throw in java • trap is similar to catch • The mechanism is also familiar, a leave "bubbles" up the call stack like in java until it is handled by a trap (if ever)
Leave • Programmer can call User: : Leave(KError. Code); which corresponds to throw(Exception) in java • The execution of that function is stopped immediately and the control returns to the calling code. • Also an API function can (and most do) leave.
Trap • Trapping is done with a marco TRAP (or TRAPD). • The code is executed onward from the next line after a TRAP (stops "bubbling") • The macro takes 2 parameters: a TInt to store the leave code and the name of the function to be executed TInt Leave. Result; TRAP(Leave. Result, func 1());
Example code void func 1() { TInt result; result = somefunc(); if(result) { User: : Leave(KSome. Error); } } void Test. Func() { TInt Leave. Result; TRAP(Leave. Result, func 1()); if(Leave. Result) { // Leave happened in func 1() that has to be handled } }
Example code void func 1() { TInt result; result = somefunc(); if(result) { User: : Leave(KSome. Error); } } void Test. Func() { TRAPD(Leave. Result, func 1()); // Defines Leave. Result if(Leave. Result) { // Leave happened in func 1() that has to be handled } }
Trap return values • If leave does not occur KErr. None, integer 0 is returned. • In trap, the return value of the function can also be saved: TRAPD(Leave. Result, resval = func 1());
Leave functions • User: : namespace has a set of static API leave functions: • User: : Leave(leavecode); • User: : Leave. No. Memory(); //KErr. No. Memory • User: : Leave. If. Error(leavecode); // If leavecode is negatice, leave with error as the reason. • User: : Leave. If. Null(TAny *pointer); //KErr. No. Memory as the reason
The L suffix • Symbian uses a convention to use a suffix L in functions that may leave • This is to signal the programmer that it may be necessary to trap such a function • Unless trapped, the code to follow might not be executed
A couple words about memory • In contrast to Java, in C++ you must actively free any memory you have allocated. • Not doing so will result in leaking of memory. • Usually you use new to generate new objects and delete to destroy them • Also, it is a good practice to set pointers to null after they no longer point to an object
Leaving and memory What if? void func 1() { CSome. Object *test. Obj = new CSome. Object; TInt result = test. Obj. somefunc(); // which may leave delete test. Obj; test. Obj = null; } void Test. Func() { TRAPD(Leave. Result, func 1()); // Defines Leave. Result if(Leave. Result) { // Leave happened in func 1() that has to be handled } }
Cleanup • Obviously, we have a problem • Since leave can result in skipping some code, we must be careful with allocated memory not to have code that leaks • In previous example test. Obj is an automatic variable that goes out of scope when func 1 exits • Result: the created object is left in the memory and cannot be deleted
Cleanup stack • The solution to our problem is something called a cleanup stack • It can be thought of a storage of pointers to created objects (which might otherwise be lost) • Think of it as a memory accounting device • push • pop
Cleanup stack • Items that must be cleaned are pushed into the stack • If leave occurs, these items are automatically popped from the stack and deleted • If no leave occurs, you must pop the items yourself • Watch out for double deletion
An example void my. Testfunc() { CTest. Obj *obj = new CTest. Obj(); Cleanup. Stack: : Push. L(obj); My. Other. Func. L(); // may leave Cleanup. Stack: : Pop(); delete obj; }
An example void my. Testfunc() { CTest. Obj *obj = new CTest. Obj(); Cleanup. Stack: : Push. L(obj); My. Other. Func. L(); // may leave Cleanup. Stack: : Pop. And. Destroy(); delete obj; // WRONG! obj already deleted }
Creating a cleanup stack • Cleanup stack is automatically created for GUI applications • For your own threads you have to create the cleanup stac yourself • CTrap. Cleanup *clstack = CTrap. Cleanup: : New() • remember to delete the stac when finished • delete clstack;
Object types • Push. L(CBase *) – delete is called when object is popped – calls the destructor of the derived class • Push. L(TAny *) – User: : Free() is called when object is popped – destructor is not called
What if Push. L leaves? • What if there is no space in the stack? • Symbian always keeps at least one free spot on the cleanup stack. • If the Push. L leaves, the pushed item will still be pushed to the stack • Allocating the next slot may fail resulting Push. L leaving
Complex cleanup • Sometimes we have objects that require more complex cleanup than just delete • Push. L(TCleanup. Item user. Cleanup) • TCleanup. Item is a wrapper class for a function that handles cleanup
Other cleanup functions • Cleanup. Close. Push. L <class T>(T& obj) • Pop calls obj. Close() • used mainly for R classes, which require Close() to be called • Cleanup. Release. Push. L<class T>(T& obj) • calls Release()
Other cleanup functions • Cleanup. Delete. Push. L <class T>(T& obj) • Using templates, the pop function calls the actual destructor of the object regardless of the type of the object • Hence, the object doesn't have to be derived from CBase • you should use this for all non CBase derived classes that have a destructor.
Templates • Were created to make function code reuse possible (instead of just overloading functions) • Templates basically achieve the same as a superclass in Java
LC functions • LC suffix denotes functions that automatically push a reference of a created object to the cleanup stack • For example: User: : Alloc. LC(100) allocates memory and pushes a pointer to the cleanupstack • No need for User: : Push. L(. . . )
Leave in object creation • The new operation may fail due to inadequate memory. • You can use a ELeave when calling the constructor to assure that leave occurs if object creation (new operation) fails • CMy. Object *obj = new (ELeave) CMy. Object; • Constructor itself should never leave (why? )
Two phase constructors • After creating the object with new we call a constructor function which may leave • This call can be trapped • Often we name this function as Construct. L
Construct. L void test. L() { CTest. Obj *o = new (ELeave) CTest. Obj; Cleanup. Stack: : Push. L(o); o->Construct. L(); . . . }
Panics • Don' t panic • The operating system may do that. • An unrecoverable error that causes the thread to finish • User: : panic(const TDes &Category, TInt reason) • On the device the execution ends and the device shows a dialog box
Libraries • static (linked at build) • DLLs (Dynamic Link Library) – loaded and linked at runtime – one copy is shared by multiple programs
- Slides: 39