1. Trang chủ
  2. » Công Nghệ Thông Tin

Symbian OS ExplainedEffective C++ Programming for Smartphones phần 10 potx

42 194 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Good Code Style
Trường học University of Technology
Chuyên ngành Computer Science
Thể loại Bài luận
Năm xuất bản 2023
Thành phố Hanoi
Định dạng
Số trang 42
Dung lượng 279,5 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

21.3 Use Stack Memory Carefully For a target mobile phone running Symbian OS, the program stacksize defaults to 8 KB,4 and it doesn’t grow when that size is exceeded.Actually that’s not

Trang 1

void CSwipeCard::ChangeSecurityDetailsL() // Alternative implementation {// MakePasswordAndPINL() has been split into two for simplicity CPIN* tempPIN = MakePINL(); // Create a temporary PIN

a single large block of memory and use it to store objects within an array

Degrade Gracefully – Leave if Memory Allocation Is Unsuccessful

You should code to anticipate low memory or other exceptional tions To save you coding a check that each and every heap allocationyou request is successful, Chapter 2 describes the overload of operatornewwhich leaves if there is insufficient heap memory for the allocation.Leaves are the preferred method of coping with exceptional conditionssuch as low memory on Symbian OS When a memory failure occursand causes your code to leave, you should have a higher level TRAP to

condi-”catch” the failure and handle it gracefully (for example, by freeing somememory, closing the application, notifying the user, or whatever seemsmost appropriate)

Symbian OS runs on limited-resource mobile phones which will, attimes, run out of memory So you must prepare your code to cope underthese conditions To help you verify that your code performs safely underlow memory conditions, Symbian OS provides a variety of test tools andmacros that you can use in your own test code to simulate low memoryconditions I described these in detail in Chapter 17

Check that Your Code Does not Leak Memory

I’ve already discussed how to prevent memory leaks, but, of course, thisdoesn’t mean that they won’t occur It is important to test your coderegularly to check that it is still leave-safe and that no leaks have beenintroduced by maintenance or refactoring Symbian OS provides macrosand test tools to test the heap integrity and to show up leaks when your

Trang 2

USE STACK MEMORY CAREFULLY 325

code unloads I describe how to use these in Chapter 17 Leaks can bedifficult to track down, so it is far easier to test for them as part of theregular testing cycle, in order to catch regressions close to the time atwhich they are introduced

21.3 Use Stack Memory Carefully

For a target mobile phone running Symbian OS, the program stacksize defaults to 8 KB,4 and it doesn’t grow when that size is exceeded.Actually that’s not quite true, because the Symbian OS emulator running

on Windows will extend the program stack if the size exceeds the limit.Consequently, you may find that your application runs perfectly well onthe emulator, while it overflows the stack on hardware

So what happens when you outgrow the stack space available? Furtherattempts to use the stack will result in access to a memory address that’snot mapped into the address space for your process This causes an accessviolation that will generate an exception – at which point the kernel willpanic your code with KERN-EXEC 3 In fact, if you try to build codewhere any single function tries to allocate automatic variables occupyingmore than 4 KB, you will receive an unresolved external chkstk linkerror However, this only considers static allocation and doesn’t take intoaccount recursion, variable length looping or anything else that can only

be calculated at runtime

Both the size of the program stack, which is significantly smaller thanmost desktop applications have available, and the fact it does not growdynamically, make it important that your stack usage is conservative

Manage Recursive Code Carefully

Recursive code can use significant amounts of stack memory To ensurethat your code does not overflow the stack, you should build in a limit tothe depth of recursion, where this is possible It’s a good idea to minimize

4 For a component running in a separate process, e.g a server or exe, you can change the stack size from the default 8 KB, by adding the following to your mmp file to specify a new stack size in hexadecimal or decimal format For example:

epocstacksize 0x00003000 // 12 KB

Alternatively, you can create a new thread and specify a chosen stack size, as described

in Chapter 10 This is particularly useful if your application makes heavy use of the stack, say through recursion, and needs more space than the default stack size makes available.

If you do hit the limit, it’s worth considering why your code is using so much stack space before assigning more, because consumption of extra stack resources leaves less free for other programs There are valid reasons why you may need more stack, but you may alternatively wish to consider modifying the program architecture or employing some of the tips described here.

Trang 3

the size of parameters passed into recursive code and to move localvariables outside the code.

Consider the Effect of Settings Data on Object Size

To minimize object size where a class has a large amount of state orsettings data, you may be able to use bitfields to store it rather than32-bit TBools or enumerations (in fact, this applies equally to stack- andheap-based classes) A good example of this is the TEntry class which ispart of F32, the filesystem module A TEntry object represents a singledirectory entry on the filesystem, and keeps track of its attributes (such

as whether it is marked read-only or hidden), its name and its size TheTEntryclass is defined in f32file.h – it has a single TUint whichstores the various attributes, each of which is defined in the header file

as follows:

const TUint KEntryAttNormal=0x0000;

const TUint KEntryAttReadOnly=0x0001;

const TUint KEntryAttHidden=0x0002;

const TUint KEntryAttSystem=0x0004;

const TUint KEntryAttVolume=0x0008;

const TUint KEntryAttDir=0x0010;

const TUint KEntryAttArchive=0x0020;

class TEntry

{ public:

IMPORT_C TBool IsReadOnly() const;

IMPORT_C TBool IsHidden() const;

IMPORT_C TBool IsSystem() const;

IMPORT_C TBool IsDir() const;

IMPORT_C TBool IsArchive() const;

TBool TEntry::IsReadOnly() const

{ return(iAtt&KEntryAttReadOnly);

} TBool TEntry::IsHidden() const

{ return(iAtt&KEntryAttHidden);

Trang 4

USE STACK MEMORY CAREFULLY 327

This is all quite straightforward and transparent to client code becausethe function returns a boolean value, although it doesn’t store the attribute

as such As I’ve mentioned previously, you should aim to keep your classintuitive to use and maintain While you may be able to shave a few bytesoff the class by using bitfields, you need to consider the impact this mayhave on the complexity of your code, and that of your clients

Use Scoping to Minimize the Lifetime of Automatic Variables

Simple changes to the layout of code can make a significant difference tothe amount of stack used A common mistake is to declare all the objectsrequired in a function at the beginning, as was traditional in C code.Consider the following example, which is flawed because it declaresthree large objects on the stack before they are all immediately necessary

void CMyClass::ConstructL(const TDesC& aDes1, const TDesC& aDes2)

{ TLarge object1;

allo-By prolonging the lifetime of these objects, the code is wasting valuablestack space, which may prevent FinalResultL() from obtaining thestack space it requires

A better code layout is as follows, splitting the code into two separatefunctions to ensure the stack space is only used as it is required, at theexpense of an extra function call Note that, because the parameters areall passed by reference, no additional copy operations are performed topass them to the separate function

void CMyClass::DoSetupAndCombineL(const TDesC& aDes1,

const TDesC& aDes2, TLarge& aObject) {

TLarge object1;

object1.SetupL(aDes1);

TLarge object2;

Trang 5

aObject = CombineObjectsL(object1, object2);

} void CMyClass::ConstructL(const TDesC& aDes1, const TDesC& aDes2)

{ TLarge object3;

DoSetupAndCombineL(aDes1, aDes2, object3);

void CSupermarketManager::IncreaseFruitPrices(TInt aInflationRate)

{ FruitSection()->UpdateApples(aInflationRate);

void CSupermarketManager::IncreaseFruitPrices(TInt aInflationRate)

Trang 6

ELIMINATE SUB-EXPRESSIONS TO MAXIMIZE CODE EFFICIENCY 329

CFruitSection* theFruitSection = FruitSection();

void CExample::Increment(TInt aValue)

void CExample::Increment(TInt aValue)

{

CCustomContainer& theContainer = *iContainer;

for (TInt index=0;index<theContainer.Count();index++)

(Rather than creating another variable to hold the count, I’ve simplyreversed the for loop so it starts from the last entry in the container Thishas no effect on the program logic in my example, but if you know you

Trang 7

have to iterate through the contents of the array in a particular order, youcan just create a separate variable to store the count, which is still moreefficient than making multiple calls to retrieve the same value.)

void CExample::Increment(TInt aValue)

{ CCustomContainer& theContainer = *iContainer;

for (TInt index=theContainer.Count(); index>=0;) {

if (theContainer[index]>0) theContainer[index]+=aValue;

} }

In the code that follows, I’ve added another optimization, whichstores the integer value retrieved from the array from the first call tooperator[], rather than making two separate calls to it This is anoptional enhancement, which probably depends on the percentage ofthe array to which the if statement applies As a general rule, I tend tostore retrieved values if they are used twice or more, when I know theyare constant between uses

void CExample::Increment(TInt aValue)

{ CCustomContainer& theContainer = *iContainer;

for (TInt index=theContainer.Count(); index>=0;) {

TInt& val = theContainer[index];

if (val>0) val+=aValue;

} }

21.5 Optimize Late

The sections above offer a number of suggestions to improve the style

of your code, concentrating on reducing memory usage and code sizeand increasing efficiency You should bear them in mind, bringing themnaturally into your code ”toolbox” to make your Symbian OS codemore effective

However, a note of caution: don’t spend undue amounts of timeoptimizing code until it is finished and you are sure it works Of course,you should always be looking for an optimal solution from the start,using good design and writing code which implements the design whilebeing simple to understand and maintain A typical program spends most

of its time executing only a small portion of its code Until you have

Trang 8

SUMMARY 331

identified which sections of the code are worthy of optimization, it isnot worth spending extra effort fine-tuning the code When you haveprofiled your code, you will know what to optimize and can consider thetips above Then is the time to take another look at the code and see ifthe general rules I’ve mentioned here (minimizing stack usage, releasingheap memory early and protecting it against leaks, and coding efficientlywhen the compiler cannot make assumptions for you) can be applied.And finally, you may find it useful to look at the assembler listing ofyour code You can generate this using the Symbian OS command lineabld tool, the use of which will be described in detail in your SDKdocumentation

abld listinggenerates an assembler listing file for the source filesfor a project For a project with a single source file, testfile.cpp,abld listing winscw udebcreates an assembler listing file (test-file.lst.WINSCW) for the code in testfile.cpp You can inspectthis to find out which optimizations have been applied by the compiler,before coding the optimization yourself The listing will also give you anidea of which code idioms are particularly ”expensive” in terms of thenumber of instructions required

21.6 Summary

To program effectively on Symbian OS, your code needs to be robust,efficient and compact While many of the rules for writing high qualityC++ are not specific to Symbian OS, this chapter has focused on a fewguidelines which will definitely improve code which must work withlimited memory and processor resources and build with a small footprint

to fit onto a ROM The chapter reviewed some of the main areas covered

by the Symbian OS coding standards and described the main principlesthat developers working on Symbian OS adhere to, namely minimizingcode size, careful memory management for both stack and heap memoryand efficiency optimization

You can find more advice on writing good C++ in the books listed inthe Bibliography

Trang 10

Code Checklist

The following list is based on the internal Symbian Peer Review Checklist

Declaration of Classes

• A class should have a clear purpose, design and API

• An exported API class should have some private reserved declarationsfor future backward compatibility purposes

• The API should provide the appropriate level of encapsulation, i.e.member data hiding

• Friendship of a class should be kept to a minimum in order to preserveencapsulation

• Polymorphism should be used appropriately and correctly

• A class should not have exported inline methods

• A non-derivable class with two-phase construction should make itsconstructors and ConstructL() private

• const should be used where possible and appropriate

• Overloaded methods should be used in preference to default eters

param-• Each C class should inherit from only one other C class and haveCBaseas the eventual base class

• Each T class should have only stack-based member variables

• Each M class should have no member data

Trang 11

• Header files should include the correct #ifndef #define

#endifdirective to prevent multiple inclusion

• The number of IMPORT_C tags should match the correspondingEXPORT_Ctags in the cpp file

Comments

• Comments should match the code

• Comments should be accurate, relevant, concise and useful

• Each class should have ”in-source” documentation of its purpose inheader file

• Each method should have ”in-source” documentation of its purpose,parameters and return values in the cpp file

Constructors

• A CBase-derived class does not need explicit initialization

• Member data of T and R classes should be explicitly initializedbefore use

• Member data should be initialized in the initializer list as opposed tothe body

• A C++ constructor should not call a method that may leave

• Two-phase construction should be used if construction can fail withanything other than KErrNoMemory

• NewL() and NewLC() methods should wrap allocation and struction where necessary

Trang 12

• Member pointers deleted outside the destructor should be set to NULL

or immediately re-assigned another value

• A destructor should not leave

Allocation and Deletion

• For a new expression, either use new (ELeave), or check the returnvalue against NULL if leaving is not appropriate

• For a call to User::Alloc(), either use AllocL(), or check thereturn value against NULL if leaving is not appropriate

• Objects being deleted should not be on the cleanup stack or referenced

by other objects

• C++ arrays should be de-allocated using the array deletion operator,delete [] <array>

• Objects should be de-allocated using delete <object>

• Other memory should be de-allocated using the methodUser::Free (<memory>)

Cleanup Stack and Leave Safety

• If a leaving method is called during an object’s lifetime, then theobject should either be pushed on to the cleanup stack or be held

as a member variable pointer in another class that is itself safe

Trang 13

leave-• An object should not simultaneously be owned by another object andheld on the cleanup stack when a leaving method is called.

• Calls to CleanupStack::PushL() and CleanupStack::Pop()should be balanced (look out for functions that leave objects on thecleanup stack, such as NewLC())

• If possible, use the CleanupStack::Pop() and stroy() methods which take pointer parameters, because theycatch an unbalanced cleanup stack quickly

PopAndDe-• Where possible, use CleanupStack::PopAndDestroy() ratherthan Pop() followed by delete or Close()

• Local R objects should be put on the cleanup stack using ClosePushL(), usually after the object has been ”opened”

Cleanup-• Errors caught by a TRAP harness that are ignored must be clearlycommented and explained

• The code within a TRAP harness should be able to leave

• Error processing after a TRAP that ends with an unconditionalUser::Leave() with the same error code should be re-codedusing the cleanup stack

• Use the LeaveScan tool to check source code for functions that canleave but have no trailing L

Loops and Program Flow Control

• All loops should terminate for all possible inputs

• The bracing should be correct on if .else statements.

• Optimize loops by using the clearest type (do .while or while) in

• A switch statement should be used to indicate state control Eachcasestatement should contain only a small amount of code; largechunks of code should be moved into separate functions to maintainthe readability of the switch statement

Trang 14

CODE CHECKLIST 337

• There should be a default in every switch statement

• Flow control statements should be used rather than extra booleanvariables to manage program flow

• Bitmasks should be used properly (& to read, | to set, ∼ to reset)

• Unexpected events and inputs should be handled gracefully, i.e useerror returns, leaves or panics appropriately

• Hard-coded ”magic” values should not be used

• Logging statements should be informative and in useful places

• Code should be efficient, e.g do not copy things unnecessarily, donot create too many temporaries, do not use inefficient algorithms

• Casts should be in C++ style such as static_cast, pret_castor const_cast rather than in C style

reinter-• A cast should only be used where absolutely necessary and should bethe correct type for the expression

Descriptors

• Descriptor character size should be correct, i.e 8 bits for binary dataand ASCII-like text; 16 bits for explicitly Unicode text; no suffix fornormal text

• _L should not be used for literal data: use _LIT instead (except fortest code, etc.)

• Assignment to TPtr or TPtrC does not redirect the pointer; Set()

is required for that purpose

• HBufC::Des() and TBufC::Des() are not required to use theobject as an unwritable descriptor

Trang 15

• HBufC::Des() and TBufC::Des() are not required for ment: these classes define assignment operators.

assign-• Use AppendNum() or Num() to format a number instead ofTDes::AppendFormat()or Format()

• Use Append() instead of TDes::AppendFormat() or Format()

con-• Descriptors passed to asynchronous operations should persist untilthe operation completes, e.g do not use a stack-allocated descriptor

Containers

• The least-derived type of container should be used in declarations

• The initial size and granularity of the container should be appropriate

• All owned objects in the container should be destroyed (or ownershippassed) before the container is destroyed

• The appropriate container for the purpose should be used

• Thin templates should be used for any templated code

Trang 16

active object Responsible for issuing requests to

asynchronous service providers andhandling those requests on completion

Derives from CActive

8, 9

active scheduler Responsible for scheduling events to the

active objects in an event-handling program

version See also forward compatibility.

18

C function In the context of Symbian OS, this refers to a

function with a trailing C in its name, e.g

NewLC() If successful, this type of functionleaves one or more objects on the cleanupstack when it returns

3

Trang 17

Term Definition Chapter

region of RAM is mapped into contiguouslogical addresses

13

clanger The Clangers are a race of highly-civilized,

small, bright pink, long-nosed,mouse-shaped persons who stand upright

on big flappy feet (seewww.clangers.co.uk

for more information)

throughout

cleanup stack Takes responsibility for cleaning up the

objects pushed onto it if a leaveoccurs

11, 12

context switch A switch in execution between one thread

or process and another This involves savingthe context of the currently executing thread

or process (i.e its address space mappings)and restoring the context of the newlyexecuting thread or process

10, 11, 12

descriptor A string, so-called because it is

self-describing All descriptor classes derivefrom TDesC, which describes an area ofmemory used as either a string or binarydata

4, 5

descriptorize To marshal a flat data object, typically a

struct or T class, into a descriptor forinter-thread data transfer

13

DLL export table An area in the DLL which lists the DLL

addresses of exported items On Symbian

OS, these items are indexed byordinal

13

E32 Collective term for the base components of

Symbian OS

ECOM A generic framework in Symbian OS from

v7.0 for use with plug-in modules

14

Trang 18

GLOSSARY 341

on a PC running Microsoft Windows

Compare with target hardware.

13

entry point A function called when a DLL is loaded or

attached by a thread or process In Symbian

OS, the function E32Dll() is usuallycoded as the entry point

13

EPOC, EPOC32 Earlier names for Symbian OS Rumors that

this stood for ‘Electronic Piece of Cheese’

are unconfirmed

exec call A call to the kernel via a software interrupt

(see this useful paper by John Pagonis formore detailswww.symbian.com/developer/

techlib/papers/userland/userland.pdf)

10

F32 Collective term for the components making

up the Symbian OS file server

FEP (Front-End

Processor)

Allows the input of characters by a user, forexample, by handwriting recognition orvoice, and converts the input transparentlyinto text

13

file server The server thread that mediates all file

system operations All application programsthat use files are clients of this thread

11

flat buffer A dynamic buffer using flat storage, i.e a

single segment of memory (see also

backward compatibility.

18

framework A component that allows its functionality to

be extended by plug-in modules, sometimesknown as framework extensions Theframework loads the extensions as required

14

Trang 19

Term Definition Chapter

between name and ordinal, for functionsexported from a DLL It is a colloquialreference to a def file (see moduledefinition file)

Information from this library concerning thelocation of export functions in the DLL isincluded in the application’s executablefile

just-in-time (JIT) Just-in-time debugging is used to attach a

debugger to a process at the point at which

it is about to terminate

15

memory, loads processes and libraries andschedules threads for execution

10

L function A function with a trailing L in its name, e.g

NewL(), which indicates that it may leave

2

leaves when User::Leave()is called Itcauses a return to the current trap harness

2

primary base classes, and the only form ofmultiple inheritance encouraged onSymbian OS

13, 18

null thread The lowest-priority thread in the system,

belonging to the kernel It only runs whenthere is no higher priority thread to run andusually puts the phone into power-savingmode

10

Trang 20

terminates the current thread Panics tend to

be caused when assertion statementsfail

shared library.

13, 14

OS One user process may not accessanother’s memory A process may containone or more threads

10

recognizer A plug-in that examines data from a file and

returns its data (MIME) type, if recognized

request status An object that indicates the completion

status of a request, represented byTRequestStatus

8, 9

memory that can be read but not (easily)written to It holds code and data that mustpersist when the phone is switched off OnSymbian OS, it is usually identified as the Z:

it is compressed See also flat buffer.

7

Trang 21

Term Definition Chapter server call A call to the kernel in which the kernel

server thread runs on behalf of the userprogram See this useful paper by JohnPagonis for more information

www.symbian.com/developer/techlib/

papers/userland/userland.pdf

11, 12

client and a server

11, 12

shared library A library that is loaded by the DLL loader

when an executable that links to it is

loaded Compare with polymorphic

DLL.

13

static library Other executable code may link to this

library to resolve references to exportedfunctions Builds with a lib

extension

13

target hardware A phone handset running Symbian OS

(compare with emulator)

10, 13

thin template An idiom used to minimize code bloat from

the use of standard C++ templates

13

TRAP , TRAPD Trap harness macros within which

leaving code may be executed and anyleaves ”caught” Can be likened to acombination of try and catch in standardC++

they often mean UID3, the identifier for aparticular program

13

identify a Symbian OS object

13

Ngày đăng: 14/08/2014, 12:20

TỪ KHÓA LIÊN QUAN