Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 24
Текст из файла (страница 24)
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 checkthat the appended object is valid and is being inserted within the rangeof the array.Another issue is that a number of the array manipulation functionsof CArrayX, such as AppendL(), can leave, for example when thereis insufficient memory to resize the array buffer. While it is frequentlyacceptable to leave under these circumstances, in other cases (such aswhere the kernel uses the dynamic arrays) a leave is not allowed.
In thosecircumstances, the leaving functions must be called in a TRAP macroto catch any leaves. As I described in Chapter 2, the TRAP macro has aperformance overhead.The RArray classes were added to Symbian OS to solve these issuesfor simple flat arrays. These classes have significantly better performancethan CArrayX classes and do not need a TRAP harness.
They areimplemented as R classes for a lower overhead than C classes, becausethey do not need the characteristic features of a C class: zero-fill onallocation, a virtual function table pointer and creation on the heap. Forreference, the Symbian OS class types (T, C, R and M) are discussed inmore detail in Chapter 1.The searching and ordering functions of the RArray classes werealso optimized over those of the original classes and were made simplerto use.Use RArray and RPointerArray instead of CArrayX exceptwhen you need support for segmented array memory and storage ofelements of variable lengths (which is likely to be relatively rare).7.4 Dynamic Descriptor ArraysDescriptor arrays are dynamic arrays which are specialized for holdingdescriptors.
These arrays extend the dynamic array classes and aredefined in the Symbian OS Basic Application Framework Library (BAFL)component, which means that you must link against bafl.lib in orderto use them. I’ll describe them briefly – you’ll find more documentationin your preferred SDK.104DYNAMIC ARRAYS AND BUFFERSThere are two types of descriptor array, both of which are provided forboth 8-bit and 16-bit descriptors (the use of different width descriptors isdiscussed in more detail in Chapters 5 and 6):• a pointer descriptor arrayThis type of array holds only non-modifiable TPtrC descriptor elements. The pointer descriptors are added to the array, but the datathey point to is not copied.
The pointer descriptor array classesare CPtrC8Array and CPtrC16Array and derive from CArrayFixFlat<TPtrC8> and CArrayFixFlat<TPtrC16> respectively.• a general descriptor arrayThis type of array can hold any descriptor type, storing it as a nonmodifiable element. That is, an HBufC copy is created for eachdescriptor added to the array; the array itself stores pointers tothese heap descriptor copies.
The abstract base class for a buildindependent general descriptor array is CDesCArray (the explicitvariants CDesC16Array and CDesC8Array may be used wherenecessary). These classes derive from CArrayFixBase, which wasdescribed earlier in this chapter. The concrete implementation classesare 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 concretedescriptor type and thus can equally well store HBufC, TPtrC or TBufobjects in the array. These arrays take a copy of the original descriptor,which increases the amount of memory used compared to the pointerdescriptor arrays, which do not take copies.
However, it does meanthat the original descriptor can then be safely discarded when using thegeneral descriptor arrays. Pointer descriptor arrays do not take copies, sothe descriptor elements must remain in memory for the lifetime of thearray, otherwise it references invalid information.7.5 Fixed-Length ArraysAlthough this chapter is mostly about dynamic arrays, I’ll briefly mentionan alternative to them: fixed-length arrays. You may consider using fixedlength, C++ arrays when you know the number of elements that willoccupy an array.
Symbian OS provides the TFixedArray class, whichwraps a fixed-length C++ array and adds range checking. Array accessis automatically checked and can be performed in both release anddebug builds. The checking uses assertion statements (as described inFIXED-LENGTH ARRAYS105Chapter 16) and a panic occurs if an attempt is made to use an out-ofrange 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’ssome example code to illustrate a fixed-size array containing five TTaskobjects. The array can be initialized by construction or by using theTFixedArray::Copy() function. The At() function performs rangechecking in both release and debug builds, while operator[] checksfor 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 TFixedArrayTFixedArray<TTask, 5> taskArray(&tasks[0], 5);taskArray[1].iPriority = 3; // change prioritytaskArray[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 fixedand known at compile time. Once the array has been allocated, itcannot be resized dynamically, so insertion within the bounds of thearray is guaranteed to succeed.
Additionally, access to the array is fast inrelease mode.Besides range-checking, the TFixedArray class has some usefuladditional 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 maindrawbacks to the use of fixed-length arrays are that any addition to106DYNAMIC ARRAYS AND BUFFERSthe array must occur at the end and that they do not support orderingand matching.When working with fixed-length arrays, use TFixedArray insteadof a generic C++ array to take advantage of bounds-checking andthe utility functions provided.7.6 Dynamic BuffersDynamic buffers are useful for storing binary data when its size is not fixedat compile time and it may need to expand to a potentially significantsize at runtime.
Descriptors or C++ arrays can be used to store binarydata on Symbian OS, but these are not dynamically extensible; that is, afixed-length C++ array cannot be expanded and a descriptor will panicif you attempt to write off the end of the array. You can use a heapdescriptor, HBufC, and a modifiable pointer to write into it but even thenyou must manage the allocation of memory when you need to expandthe array (as described in Chapter 5).Dynamic buffers provide an alternative solution for binary data, butyou should beware of using these classes as an alternative to descriptorsfor text data. The descriptor classes have been optimized for that purpose;in addition, dynamic buffer classes store data in 8-bit buffers, so youcannot use them comfortably for 16-bit Unicode strings.When I described the underlying memory layout of the dynamicarray classes, I mentioned that they use the CBufBase-derived classesCBufFlat and CBufSeg.
CBufBase is an abstract class that providesa common interface to the dynamic buffers. This includes methods toinsert, delete, read and write to the buffer. CBufFlat and CBufSeg arethe concrete dynamic buffer classes. They are straightforward to use, asyou’ll see from the example code below. When instantiating an objectusing the static NewL() function, a granularity must be specified, whichis the number of bytes by which the buffer will be reallocated when itneeds to be resized.
For a segmented buffer, the granularity determinesthe size of a segment.Operations on dynamic buffers are all specified in terms of a bufferposition, which is an integer value indicating a byte offset into the bufferdata, and thus has a valid range from zero to the size of the buffer. TheInsertL() and DeleteL() functions shuffle the data in the buffer afterthe insertion point. For this reason, any pointers to data in the dynamicbuffers must be discarded when the data in the buffer is updated byinsertion or deletion.