Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 15
Текст из файла (страница 15)
It provides a means by which heap-based objects may be instantiated without the need to prevent construction and initialization codefrom leaving.The first phase of two-phase construction allocates an object on theheap and may perform basic initialization which cannot leave. Thesecond phase pushes the object onto the cleanup stack, to ensure itwill be cleaned up in the event of a leave, before calling any furtherconstruction code which may leave.Two-phase construction is generally performed by methods internal to the class rather than exposed to a caller, who may not appreciate that both phases of construction are required.
Typically, two-phaseconstruction is performed on Symbian OS using static NewL() andNewLC() methods (the latter leaves the constructed object on thecleanup stack). The second-phase construction method is usuallycalled ConstructL() or InitializeL() and is usually specified54TWO-PHASE CONSTRUCTIONas protected or private – as are the constructors – which enforcestwo-phase construction as the only means by which an object can beinstantiated.Two-phase construction is typically used for C classes, since T classesdo not usually require complex construction code (because they do notcontain heap-based member data) and R classes are usually createduninitialized, requiring their callers to call Connect() or Open() toassociate the R class object with a particular resource.
You can find moreinformation about the characteristics of the various Symbian OS classtypes in Chapter 1, which discusses them in detail.5Descriptors: Symbian OS StringsGet your facts first, then you can distort them as you pleaseMark TwainThe Symbian OS string is known as a ”descriptor”, because it is selfdescribing. A descriptor holds the length of the string of data it representsas well as its ”type”, which identifies the underlying memory layout ofthe descriptor data. Descriptors have something of a reputation amongSymbian OS programmers because they take some time to get usedto.
The key point to remember is that they were designed to be veryefficient on low memory devices, using the minimum amount of memorynecessary to store the string, while describing it fully in terms of its lengthand layout. There is, necessarily, some trade-off between efficiency andsimplicity of use, which this chapter illustrates. The chapter is intendedto give a good understanding of the design and philosophy of descriptors.The next chapter will show how to use descriptors most effectively bylooking at some of the more frequently used descriptor API functions anddescribing some common descriptor mistakes and misconceptions.Descriptors have been part of Symbian OS since its initial releaseand they have a well established base of documentation. Despite this,they can still appear confusing at first sight, perhaps because there arequite a number of descriptor classes, all apparently different althoughinteroperable.1 They’re not like standard C++ strings, Java strings or theMFC CString (to take just three examples) because their underlyingmemory allocation and cleanup must be managed by the programmer.But they are not like C strings either; they protect against buffer overrunand don’t rely on NULL terminators to determine the length of the string.So let’s discuss what they are and how they work – initially by looking ata few concepts before moving on to the different descriptor classes.First, I should make the distinction between descriptors and literals;the latter can be built into program binaries in ROM because they1To paraphrase Andrew Tanenbaum: The nice thing about descriptors is that there areso many to choose from.56DESCRIPTORS: SYMBIAN OS STRINGSare constant.
Literals are treated a bit differently to descriptors and I’llcome back to them later in the chapter. For now, the focus is ondescriptors.Another issue is the ”width” of the string data, that is, whether anindividual character is 8 or 16 bits wide. Early releases, up to and includingSymbian OS v5, were narrow builds with 8-bit native characters, but sincethat release Symbian OS has been built with wide 16-bit characters asstandard, to support Unicode character sets. The operating system wasdesigned to manage both character widths from the outset by definingduplicate sets of descriptor classes for 8- and 16-bit data. The behaviorof the 8- and 16-bit descriptor classes is identical except for Copy() andSize(), both of which are described in the next chapter.
In addition,a set of neutral classes are typedef’d to either the narrow or widedescriptor classes, depending on the build width. You can identify thewidth of a class from its name. If it ends in 8 (e.g. TPtr8) it assumesnarrow 8-bit characters, while descriptor class names ending with 16 (e.g.TPtr16) manipulate 16-bit character strings. The neutral classes have nonumber in their name (e.g. TPtr) and, on releases of Symbian OS sincev5u,2 they are implicitly wide 16-bit strings.The neutral classes were defined for source compatibility purposesto ease the switch between narrow and wide builds.
Although todaySymbian OS is always built with 16-bit wide characters, you are welladvised to continue to use the neutral descriptor classes where you donot need to state the character width explicitly.Descriptors can also be used for binary data because they don’t rely ona NULL terminating character to determine their length. The unificationof binary and string-handling APIs makes it easier for programmers and,of course, the ability to re-use string manipulation code on data helpskeep Symbian OS compact.
To work with binary data, you need to codespecifically with the 8-bit descriptor classes. The next chapter discusseshow to manipulate binary data in descriptors in more detail.So, with that knowledge in hand, we can move on to consider thedescriptor classes in general.5.1 Non-Modifiable DescriptorsAll (non-literal) descriptors derive from the base class TDesC which istypedef’d to TDesC16 in e32std.h and defined in e32des16.h(the narrow version, TDesC8, can be found in e32des8.h). Chapter 1discusses Symbian OS class naming conventions and explains what the”T” prefix represents. The ”C” at the end of the class name is more2Symbian OS v5u was used in the Ericsson R380 mobile phone. This version is alsosometimes known as ”ER5U”, which is an abbreviation of ”EPOC Release 5 Unicode”.NON-MODIFIABLE DESCRIPTORS57relevant to this discussion, however; it reflects that the class defines anon-modifiable type of descriptor, whose contents are constant.
Theclass provides methods for determining the length of the descriptor andaccessing the data.The length of the descriptor is returned, unsurprisingly, by theLength() method. The layout of every descriptor object is the same,with 4 bytes holding the length of the data it currently contains. (Actually,only 28 of the available 32 bits are used to hold the length of the descriptor data; 4 bits are reserved for another purpose, as I’ll describe veryshortly. This means that the maximum length of a descriptor is limited to228 bytes, 256 MB, which should be more than sufficient!)The Length() method in TDesC is never overridden by its subclassessince it is equally valid for all types of descriptor. However, access tothe descriptor data is different depending on the implementation of thederived descriptor classes but Symbian OS does not require each subclassto implement its own data access method using virtual functions.
It doesnot use virtual function overriding because this would place the burdenof an extra 4 bytes on each derived descriptor object, added by C++ as avirtual pointer (vptr) to access the virtual function table. As I’ve alreadydescribed, descriptors were designed to be as efficient as possible andthe size overhead to accommodate a vptr was considered undesirable.Instead, to allow for the specialization of derived classes, the top 4 bits ofthe 4 bytes that store the length of the descriptor object are reserved toindicate the type of descriptor.There are currently five derived descriptor classes, each of which setsthe identifying bits as appropriate upon construction.
The use of 4 bitsto identify the type limits the number of different types of descriptor to24 (=16), but since only five types have been necessary in current andprevious releases of Symbian OS, it seems unlikely that the range willneed to be extended significantly in the future.Access to the descriptor data for all descriptors goes through the nonvirtual Ptr() method of the base class, TDesC, which uses a switchstatement to check the 4 bits, identify the type of descriptor and returnthe correct address for the beginning of its data.
Of course, this requiresthat the TDesC base class has knowledge of the memory layout of itssubclasses hardcoded into Ptr().With the Length() and Ptr() methods, the TDesC base class canimplement all the operations you’d typically expect to perform on aconstant string (such as data access, comparison and search).
Some ofthese methods are described in detail in the next chapter, and all will bedocumented in full in your preferred SDK. The derived classes all inheritthese methods and, in consequence, all constant descriptor manipulationis performed by the same base class code, regardless of the type ofthe descriptor.58DESCRIPTORS: SYMBIAN OS STRINGSThe non-modifiable descriptor class TDesC is the base class fromwhich all non-literal descriptors derive. It provides methods todetermine the length of the descriptor and to access its data. Inaddition, it implements all the operations you’d typically expect toperform on a constant string.5.2 Modifiable DescriptorsLet’s now go on to consider the modifiable descriptor types, which allderive from the base class TDes, itself a subclass of TDesC.