Symbian Developer Library

SYMBIAN OS V6.1 EDITION FOR C++

[Index] [Glossary] [Previous] [Next]



Code efficiency


Overview

Attention paid to making code efficient in speed and particularly in resource use is always worthwhile. This section suggests some methods that should become familiar to developers for this platform.

[Top]


Stack usage

Each thread in an application has a limited standard stack space of 8Kb, which should be carefully managed. Therefore:

The last point can be illustrated with the following example:

void ABadFunction()
    {
    TBigObject Object1;
    TBigObject Object2;
    TBigObject Object3;
         GetTwoObjectValues(Object1,Object2);
    Object3=SumObjects(Object1,Object2);
    FunctionWithUnknownStackOverhead(Object3);
    }

In the above code, Object1 and Object2 persist, using stack space, throughout the lifetime of the call to FunctionWithUnknownStackOverhead(), although they are not required by that time. They should be removed from the stack before the call is made. This can be achieved as follows:

void ABetterFunction()
    {
    TBigObject Object1;

    GetTotalObjectValues(Object1);
    FunctionWithUnknownStackOverhead(Object1);
    }

void GetTotalObjectValues(TBigObject &aObject)
    {
    TBigObject Object1;
    TBigObject Object2;

    GetTwoObjectValues(Object1,Object2);
    aObject=SumObjects(Object1,Object2);
    }

By splitting the code into two functions, you ensure that the stack is used no more than required.

[Top]


Function overloads

If a function definition has default arguments, and if that function often gets called with the caller assuming the default arguments, consider providing an overloaded function that doesn't have the additional arguments. This is because every time the compiler supplies a default parameter, it generates additional code where the function is called.

For example, if you have

void FunctionOne(TInt aInt=0);

which often gets called in code by the line

FunctionOne();

then consider supplying

void FunctionOne();

the contents of which might be:

void FunctionOne()
    {
    FunctionOne(0);
    }

[Top]


Pointers and references

Using a reference as a function argument may be more efficient than using a pointer. This is because the compiler has to preserve the value of the null pointer through all conversions.

Imagine a class CXxx which derives from a mixin class MYyy, as in

class CXxx : public CBase,public MYyy {...};

Then, to pass a pointer to a CXxx to a function taking a MYyy, the compiler has to add sizeof(CBase) to the pointer, except when that pointer is NULL. If cp is a CXxx*, and Func() a function taking an MYyy*, then what happens in a call like Func(cp) is something like this:

Func((MYyy* aM)(cp==NULL ? NULL : (TUint8*)cp+sizeof(CBase)));

Null references are not possible, so no test for NULL is necessary when they are used. On ARM, converting from CXxx* to MYyy* takes 8 instructions, whereas the CXxx& to MYyy& conversion takes only two.

[Top]


Floating point maths

Floating point maths is sufficiently slow that it is worth looking to see if an alternative algorithm using only integer maths is available.

For example, given two TInts, aTop, and aBottom, instead of:

TReal a = (TReal)aTop;
TReal b = (TReal)aBottom;
TReal c = a/b+0.5;
TReal result;
Math::Round(result,c,0);
return (TInt)result;

you should use

return((2*aTop+aBottom)/(2*aBottom));

[Top]


Inline functions

Inline functions are intended to speed up code by avoiding the expense of a function call, but retain its modularity by disguising operations as functions. Before using them, however, there are two issues that you should check:

The most common cases where inline functions are acceptable are:

inline ConEnv() const { return iConEnv; };

inline TPoint::TPoint(TInt aX, TInt aY) { iX=aX; iY=aY; };

template <class T> inline T Min(T aLeft,T aRight)
{ return(aLeft<aRight ? aLeft : aRight); }

[Top]


No test for NULL pointer when deleting object

C++ specifies that delete 0 does nothing, so that you need never write code such as

if (iX)
    delete iX;