Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Symbian OS Explained - Effective C++ Programming For Smartphones (2005) [eng].pdf
Скачиваний:
60
Добавлен:
16.08.2013
Размер:
2.62 Mб
Скачать

102

DYNAMIC ARRAYS AND BUFFERS

Here’s the modified version of code that uses the task manager class. It is quite similar to the previous code because the change to the encapsulated array class – which stores the tasks in CTaskManager – does not affect it:

void TestTaskManagerL()

{

CTaskManager* taskManager = CTaskManager::NewLC();

// Add tasks to the array, use the index to set the task priority _LIT(KTaskName, "TASKX%u");

for (TInt index=0; index<4; index++)

{

TBuf<10> taskName; taskName.Format(KTaskName, index); TTask task(taskName, index); taskManager->AddTaskL(task);

}

ASSERT(4==taskManager->Count());

//Add a copy of the task at index 2

//to demonstrate sorting and matching TBuf<10> taskName; taskName.Format(KTaskName, 2);

TTask copyTask(taskName, 2); taskManager->AddTaskL(copyTask);

ASSERT(5==taskManager->Count());

taskManager->RunAllTasksL();

// Remove both copies of the task taskManager->DeleteTask(copyTask);

ASSERT(3==taskManager->Count());

// Destroy the taskManager CleanupStack::PopAndDestroy(taskManager);

}

7.3 Why Use RArray Instead of CArrayX?

The original CArrayX classes use CBufBase, which allows a varied dynamic memory layout for the array using either flat or segmented array buffers. However, CBufBase works with byte buffers and requires a TPtr8 object to be constructed for every array access. This results in a performance overhead, even for a simple flat array containing fixedlength elements. Furthermore, for every method which accesses the array, there are a minimum of two assertions to check the parameters, even in release builds.

DYNAMIC DESCRIPTOR ARRAYS

103

For example, to access a position in a CArrayFixX array, operator[] calls CArrayFixBase::At(), which uses an __ASSERT_ALWAYS statement to range-check the index and then calls CBufFlat::Ptr() which also asserts that the position specified lies within the array buffer. Likewise, adding an element to a CArrayFixFlat<class T> array using AppendL() runs through two assertion statements in CArrayFixBase::InsertL() and a further two

__ASSERT_ALWAYS checks in CBufBase::InsertL(), which check that the appended object is valid and is being inserted within the range of the array.

Another issue is that a number of the array manipulation functions of CArrayX, such as AppendL(), can leave, for example when there is insufficient memory to resize the array buffer. While it is frequently acceptable to leave under these circumstances, in other cases (such as where the kernel uses the dynamic arrays) a leave is not allowed. In those circumstances, the leaving functions must be called in a TRAP macro to catch any leaves. As I described in Chapter 2, the TRAP macro has a performance overhead.

The RArray classes were added to Symbian OS to solve these issues for simple flat arrays. These classes have significantly better performance than CArrayX classes and do not need a TRAP harness. They are implemented as R classes for a lower overhead than C classes, because they do not need the characteristic features of a C class: zero-fill on allocation, a virtual function table pointer and creation on the heap. For reference, the Symbian OS class types (T, C, R and M) are discussed in more detail in Chapter 1.

The searching and ordering functions of the RArray classes were also optimized over those of the original classes and were made simpler to use.

Use RArray and RPointerArray instead of CArrayX except when you need support for segmented array memory and storage of elements of variable lengths (which is likely to be relatively rare).

7.4 Dynamic Descriptor Arrays

Descriptor arrays are dynamic arrays which are specialized for holding descriptors. These arrays extend the dynamic array classes and are defined in the Symbian OS Basic Application Framework Library (BAFL) component, which means that you must link against bafl.lib in order to use them. I’ll describe them briefly – you’ll find more documentation in your preferred SDK.

104

DYNAMIC ARRAYS AND BUFFERS

There are two types of descriptor array, both of which are provided for both 8-bit and 16-bit descriptors (the use of different width descriptors is discussed in more detail in Chapters 5 and 6):

a pointer descriptor array

This type of array holds only non-modifiable TPtrC descriptor elements. The pointer descriptors are added to the array, but the data they point to is not copied. The pointer descriptor array classes are CPtrC8Array and CPtrC16Array and derive from CArrayFixFlat<TPtrC8> and CArrayFixFlat<TPtrC16>respectively.

a general descriptor array

This type of array can hold any descriptor type, storing it as a nonmodifiable element. That is, an HBufC copy is created for each descriptor added to the array; the array itself stores pointers to these heap descriptor copies. The abstract base class for a buildindependent general descriptor array is CDesCArray (the explicit variants CDesC16Array and CDesC8Array may be used where necessary). These classes derive from CArrayFixBase, which was described earlier in this chapter. The concrete implementation classes are CDesCXArrayFlat (for flat array storage) or CDesCXArraySeg

(for segmented storage), where X = 8, 16, or is not declared explicitly.

There are advantages and disadvantages of each type. General descriptor arrays are useful because you do not have to use a particular concrete descriptor type and thus can equally well store HBufC, TPtrC or TBuf objects in the array. These arrays take a copy of the original descriptor, which increases the amount of memory used compared to the pointer descriptor arrays, which do not take copies. However, it does mean that the original descriptor can then be safely discarded when using the general descriptor arrays. Pointer descriptor arrays do not take copies, so the descriptor elements must remain in memory for the lifetime of the array, otherwise it references invalid information.

7.5 Fixed-Length Arrays

Although this chapter is mostly about dynamic arrays, I’ll briefly mention an alternative to them: fixed-length arrays. You may consider using fixedlength, C++ arrays when you know the number of elements that will occupy an array. Symbian OS provides the TFixedArray class, which wraps a fixed-length C++ array and adds range checking. Array access is automatically checked and can be performed in both release and debug builds. The checking uses assertion statements (as described in

FIXED-LENGTH ARRAYS

105

Chapter 16) and a panic occurs if an attempt is made to use an out-of- range array index. The class can be used as a member of a CBase class (on the heap) or on the stack, since it is a T class.

The class is templated on the class type and the size of the array. Here’s some example code to illustrate a fixed-size array containing five TTask objects. The array can be initialized by construction or by using the TFixedArray::Copy() function. The At() function performs rangechecking in both release and debug builds, while operator[] checks for out-of-range indices in debug builds only.

class TTask

{

public:

TTask(TInt aPriority); public:

TInt iPriority; };

TTask::TTask(TInt aPriority) : iPriority(aPriority){}

void TestFixedArray()

{

TTask tasks[5]={TTask(0), TTask(1), TTask(2), TTask(3), TTask(4)};

//Wrap tasks with a range-checked TFixedArray TFixedArray<TTask, 5> taskArray(&tasks[0], 5); taskArray[1].iPriority = 3; // change priority taskArray[5].iPriority = 3;

//Assertion fails -> panics debug builds (USER 133) taskArray.At(5).iPriority = 3;

//Assertion fails -> panics debug & release builds

}

These arrays are convenient where the number of elements is fixed and known at compile time. Once the array has been allocated, it cannot be resized dynamically, so insertion within the bounds of the array is guaranteed to succeed. Additionally, access to the array is fast in release mode.

Besides range-checking, the TFixedArray class has some useful additional functions which extend a generic C++ array. These include:

Begin() and End() for navigating the array

Count(), which returns the number of elements in the array

Length(), which returns the size of an array element in bytes

DeleteAll(), which invokes delete on each element of the array

Reset(), which clears the array by filling each element with zeroes.

Besides having to know the size of the array in advance, the main drawbacks to the use of fixed-length arrays are that any addition to