Wiley.Developing.Software.for.Symbian.OS.2nd.Edition.Dec.2007 (779887), страница 41
Текст из файла (страница 41)
Also, ifyou insert data anywhere in the buffer, then, since all data is shifted up,a memory allocation may occur too.Use Delete() to delete a specified number of bytes at the specified dynamic buffer position. Upon deletion, the data is shifted downappropriately (as is also done in the Delete() descriptor method).Manually changing the size of a dynamic bufferEven though InsertL() will expand the buffer size automatically asneeded, you may still want to manually change the size of your buffer.There are two reasons for this:TEMPLATES IN SYMBIAN OS2031.
So that you will know immediately if you have enough memory forthe particular sequence of data writes you are performing.2. So that the allocation is done at once, for efficiency, instead of manyallocations taking place as you insert new data.ResizeL() and ExpandL() will manually reserve space in the dynamicbuffer.
These functions are similar in that they force a reallocation of thebuffer.ResizeL() we’ve seen in the example – it simply causes the dynamicbuffer to be reallocated (or initially allocated) to a new size, with thebuffer space increasing or decreasing as appropriate.ExpandL() inserts an uninitialized data region at a given bufferposition, thus forcing the buffer size to increase by that amount. In otherwords, it sets aside some space in the buffer for future use.For example:dynbuf->ExpandL(5,200);would insert an uninitialized data region at position 5 to 200, pushingthe rest of the data up (and doing a memory allocation if needed).
Thiscarves out a space in the buffer so that you can now use Write() towrite to that region, knowing that the memory is preallocated.Getting a pointer to an area in a dynamic bufferPtr() returns a TPtr8 that points to the address of the specified positionin the dynamic buffer. Ptr(4), for example, returns a TPtr8 referencingthe region starting at the byte at position 4 in the buffer up to either thebuffer end or – in the case of a segment buffer – the end of the currentsegment.BackPtr() returns a TPtr8 that points to the memory region, startingat the beginning of the contiguous memory region containing the byte,and ending at the position specified when calling BackPtr().
For a flatbuffer, the beginning will always be the first byte of the buffer. For asegmented buffer, it will be the first byte of the segment containing thebyte.6.7 Templates in Symbian OSBefore I cover arrays, now is a good time to look at how templates areused in Symbian OS. Let’s begin with a quick review of C++ templates ingeneral.204STRINGS, BUFFERS, AND DATA COLLECTIONSNormally in C++, specifying a variable’s data type is done at compiletime and thus remains fixed while a program is running. This can belimiting in many cases. For example, if you want to create a list classwhere you do not care what type of objects are on the list, yet want toimplement a common set of operations on them, then you would eitherneed to deal with your data as void* (TAny* on Symbian OS), whichrequires the class user to cast the data thus losing your compiler typechecking, or you would need to create one list class for each list itemdata type and duplicate the list operation code in each class.
Neither ofthese is desirable. Templates solve this type of situation by providing away for data types to be abstracted in the code and passed as parametersat runtime. For example:template<typename T>class TMyClass{public:// constructorTMyClass() { };AddItem(T aItem);private:T iItems[100];};template<typedef T> specified that T represents a data type, whichis passed in at runtime. So if someone instantiated the class as:TMyClass<TInt> myclass;then TMyClass would act as if it were defined as:class TMyClass{public:TMyClass() { };AddItem(TInt aItem);private:TInt items[100];};In other words, it would substitute the template parameter T with the datatype TInt.You can also pass values that are not data types to templates.
Belowis the same example, but also specifying the size of the allocated itemsarray using a template value:template<typenameclass TMyClassT ,TIntaMaxsize >ARRAYS205{public:TMyClass() { }AddItem(T aItem);private:T iItems[aMaxsize];};An example of instantiating this template class is:TMyClass<char,500> myclass;which will cause T to be substituted with char in TMyClass, and 500to be the size of the iItems array.Symbian OS uses an idiom for templates known as thin templates. Thisconsists of having a private base class that implements core functionalityusing the TAny* data type to provide type-independent functionality.The thin template class inherits from this base class and acts as a thinlayer above it (hence the name).
The data types (and/or any values) arepassed to the thin template class at runtime using the C++ templatesyntax when the class is instantiated. The thin template methods acceptthe data type specified to the template, cast the data down to TAny*,and call the corresponding base class functions. So even though thebase class uses the TAny* data type, the thin template class, whichthe user uses, provides the type checking since it uses templates. I willnot go into further detail about how thin templates are implementedin Symbian OS – since this is hidden from you and this knowledgeis not needed – but having a basic understanding of templates helpsunderstand the syntax when using template-based classes in SymbianOS.The array classes described in the next section use thin templates.6.8 ArraysSymbian provides a large assortment of API classes for implementing dataarrays.
The Symbian OS Library in the SDK documentation provides acomplete list of these classes, as well as their method descriptions. I willcover the key array classes here and provide some examples.6.8.1Fixed ArraysTFixedArray is a thin API class that uses templates to define an array ofdata items of user-defined type. The class overrides the [] operator andthus acts like a traditional array, but with an important difference – rangechecking is performed on indexes to prevent out-of-bound accesses.206STRINGS, BUFFERS, AND DATA COLLECTIONSA fixed array is declared as follows:TFixedArray<type,size> myArrayThis line will allocate a fixed array called myArray, where type represents the data type of the data in the array and size indicates themaximum number of MyObjs the array is allocated for.This declaration is effectively the same as type myArray[size].The following is an example of using fixed arrays:/* Initialize a simple fixed array of integers */TFixedArray<TInt,10> array;for (j=0;j<10;j++){array[j] = j;}array[10] = 10; // Causes a panic, outside of array boundaryFixed arrays are a lightweight and efficient way of implementing thearray while providing access range checking.
Like traditional arrays, thenumber of items in the array is preallocated at compile time.In addition to providing range checking, TFixedArray also providessome useful methods such as Reset() to clear the entire array with zeros,DeleteAll() to invoke delete on each array element, Count() toreturn the number of elements in the array, and Length() to return thesize of an array element in bytes. Begin() and End() methods are alsoprovided for navigating the array.6.8.2 Descriptor ArraysDescriptor array classes implement arrays of TDesC-based buffer descriptors. The purpose of these classes, in most cases, is to implement an arrayof strings. For example, a list box keeps its list of selection item strings ina descriptor array.Descriptor arrays use dynamic buffers to store their data.
Therefore,the array size does not need to be preallocated, as it is for a fixed array.The array is expanded as needed when new data items are added to it.Descriptor arrays can be flat or segmented, contain 8- or 16-bitdescriptors, and contain either copies of the descriptors (in HBufC’s) orpointers to descriptors (in TPtr’s).Here are the instantiable descriptor array classes:•CDesC16ArrayFlat: An array of 16-bit descriptors stored in a flatdynamic buffer.• CDesC16ArraySeg: Same as CDesC16ArrayFlat, but data isstored in a segmented dynamic buffer.•CDesC8ArrayFlat: An array of 8-bit descriptors stored in a flatdynamic buffer.ARRAYS207•CDesC8ArraySeg: Same as CDesC8ArrayFlat, but data is storedin a segmented dynamic buffer.•CDesCArrayFlat: Same as CDesC16ArrayFlat for the standardUnicode build.•CDesCArraySeg: Same as CDesC16ArraySeg for the standardUnicode build.•CPtrC16Array: Array of TPtrC objects that point to the descriptordata elements.•CPtrC8Array: Same as CPtrC16Array, but stores 8-bit descriptors.•CPtrCArray: Equivalent to CPtrC16Array for the standard Unicode build.Descriptor array classes that end in Flat and Seg indicate the flat andsegmented type of dynamic buffer used to store the array’s data.
Refer tothe previous section on dynamic buffers for more information. Use a flatarray if the array is not expanded very often, otherwise use a segmentedarray.Note that the classes that begin in CPtrC use flat buffers only – nosegmented versions of these classes are supplied.Descriptor array classes that begin with CDesC are implemented asan array of HBufC pointers. When a descriptor is added to a CDesCarray, the array class will allocate a new HBufC, copy the data from thedescriptor to this HBufC, and, finally, write the HBufC’s pointer to theappropriate position in the array. For example:_LIT(KString1, "My String");_LIT(KString2, "Test One Two");TBufC<20> MmDes(KString1);TBuf<20> MmDes1(KString2);CDesCArrayFlat myArray = new (ELeave) CDesCArrayFlat(5);CleanupStack::PushL(myArray); // in case the appends leavemyArray->AppendL(myDes);myArray->AppendL(myDes1);/* ...