Wiley.Symbian.OS.C.plus.plus.for.Mobile.Phones.Aug.2007 (779890), страница 26
Текст из файла (страница 26)
If the return type was a reference to one of the descriptor types,then random stack data would be returned.116DESCRIPTORSReturning an entire non-constant descriptorIf you are returning an entire descriptor that exists while the caller ofthe method uses it and the descriptor is to be modified, then you shouldreturn TDes&:TDes& CSomeClass::ReturnWritableEntireDescriptor(){return iDescriptor;}someClass->ReturnWritableEntireDescriptor() = KTxtHello;Returning a partial non-constant descriptorIf you are returning part of a descriptor that exists while the caller ofthe method uses it and the descriptor is to be modified, then you shouldreturn TPtr&:TPtr& CSomeClass::ReturnWritablePartialDescriptor(){iTPtr.Set(iDescriptor.MidTPtr(1, 5);return iTPtr;}someClass->ReturnWritablePartialDescriptor() = KTxtHello;In this example, assuming iDescriptor is of type TBuf<x>, then itis not possible to return iDescriptor.MidTPtr(1,5) as that wouldresult in a reference to a temporary TPtr being returned.
Similarly, itis not sufficient to assign the result of iDescriptor.MidTPtr(1,5)into a locally declared TPtr as that too would result in a reference to atemporary object being returned. Hence, it is necessary to have a TPtrdata member and return a reference to it.Note that the MidTPtr(), LeftTPtr() and RightTPtr() methodsof TDes all return a TPtr while the Mid(), Left() and Right()methods of TDesC return a TPtrC.Returning constant raw dataIf you are returning in its entirety raw data that exists while the caller ofthe method uses it and the data is not to be modified, then you shouldreturn const TDesC& or TPtrC or, as raw data is being dealt with, morelikely the narrow variants TDesC8 or TPtrC8:class CSomeClass : public CBase{public:USING DESCRIPTORS WITH METHODS117// methods omitted for brevityprivate:TText8 iRawData[KMaxLength];mutable TPtrC8 iPtrC;};TPtrC8 CSomeClass::ReturnConstantEntireRawData() const{return iRawData;}If the return type is TPtrC8 then the raw data can be returned directly;if the return type is const TDesC8& then the raw data must first beconverted to a descriptor via a TPtrC8 or TPtr8:const TDesC8& CSomeClass::ReturnConstantEntireRawData() const{iPtrC.Set(iRawData, KMaxLength);return iPtrC;}Note that iPtrC has been declared as mutable, otherwise a compilation error results when Set() is called as ReturnConstantEntireRawData() is a const method.Returning a portion of constant raw dataIf you are returning a portion of raw data that exists while the caller of themethod uses it and the data is not to be modified, then you should returnTPtrC:TPtrC8 CSomeClass::ReturnConstantPartialRawData() const{// if iRawData contains "Hello World!",// return a pointer to "World!"iPtrC.Set(iRawData, KMaxLength);return iPtrC.Right(6);// oriPtrC.Set(&iRawData[5], 6);return iPtrC;}TPtrC8 ptr = someClass->ReturnConstantPartialRawData();// ptr points to "World!"Returning modifiable raw dataIf you are returning in its entirety raw data that exists while the caller ofthe method uses it and the data is to be modified, then you should return118DESCRIPTORSTDes&.
You need to construct a non-temporary TPtr around the rawdata and return that:class CSomeClass : public CBase{public:// methods omitted for brevityprivate:TText8 iRawData[KMaxLength];TPtr8 iPtr;};TDes8& CSomeClass::ReturnWritableEntireRawData(){iPtr.Set(iRawData, dataLength, KMaxLength);return iPtr;}TPtr does not have a default constructor so, when it is used as a datamember of a class, it must be initialized in the constructor initializationlist (see Section 5.11 for more information).Returning a portion of modifiable raw dataIf you are returning raw data that exists while the caller of the methoduses it, and the data is to be modified, then you should return TDes&.You need to construct a TPtr around the raw data and return that:TDes8& CSomeClass::ReturnWritablePartialRawData(){iPtr.Set(iRawData, dataLength, KMaxLength);iPtr = iPtr.RightTPtr(6);return iPtr;// oriPtr.Set(&iRawData[5], 6);return iPtr;////////////}as always when returning references, be careful not toreturn a reference to a temporary object, so avoid codesuch as the following:iPtr.Set(iRawData, dataLength, KMaxLength);return iPtr.RightTPtr(6);RightTPtr() returns a TPtr objectReturning a constant descriptor by valueIf the data to be returned has to be constructed and has a known maximumlength which is less than or equal to 2569 then return a TBufC or TBuf.If the data is large, create and return a heap descriptor.9Returning a descriptor by value like this consumes stack space.
Objects bigger than256 bytes should not be placed on the stack.USING DESCRIPTORS WITH METHODS119const TInt KBufferSize = 64;typedef TBuf<KBufferSize> TMyBufferType;class CSomeClass : public CBase{public:TMyBufferType ReturnByValue() const;...private:TMyBufferType iBuf;};TMyBufferType CSomeClass::ReturnByValue() const{return iBuf;}CSomeClass* someClass = CSomeClass::NewL();TMyBufferType myBuffer(someClass->ReturnByValue());Creating a heap descriptor and returning ownershipIf the descriptor has to be constructed and its length is long or not fixedthen allocate and return an HBufC:HBufC* CSomeClass::GetSomeTextL(){HBufC* hBuf = iEikonEnv->AllocReadResourceL(someResourceID);return hBuf;}HBufC* hBuf = GetSomeTextL();...delete hBuf;The caller is responsible for taking ownership of the returned heapbased descriptor and must be responsible for deleting it when it is finishedwith.If the heap descriptor is not written to or is written to infrequently thenuse HBufC; however if the heap descriptor is to be written to frequentlythen an RBuf is preferable as it is more efficient.An RBuf cannot be returned from a method as its copy constructor isprotected, thus the following code generates a compilation error:RBuf FooL(){_LIT(KTxtHello, "Hello");RBuf buf;buf.CreateL(buf);return (buf);}120DESCRIPTORSYou could attempt to return a pointer to an RBuf instead but thenmaking your code leave-safe becomes more complicated and messy.Anyway, R-type objects are intended to be used on the stack and not theheap.
Instead you should use an RBuf as a parameter.Returning a reference to a re-allocatable writable descriptorIf you want to return a writable descriptor, where you require reallocationbut do not want to transfer ownership, then return an RBuf&:class CSomeClass : public CBase{public:RBuf& ReturnWritableReallocatableDescriptor();private:RBuf iBuf;};RBuf& CSomeClass::ReturnWritableReallocatableDescriptor(){return iBuf;}RBuf& buf = someClass->ReturnWritableReallocatableDescriptor();buf.ReAllocL(KNewMaxSize);You can also return an HBufC*:class CSomeClass : public CBase{public:HBufC* ReturnWritableReallocatableDescriptor();private:HBufC* iBuf;};HBufC* CSomeClass::ReturnWritableReallocatableDescriptor(){return iBuf;}HBufC* buf = someClass->ReturnReallocatableDescriptor();if (buf != NULL){delete buf;buf = NULL;}buf.ReAllocL(KNewMaxSize);Note that both these examples are a violation of object-orientedprinciples as the private internals of a class are exposed for manipulation.SOME DESCRIPTOR OPERATIONS1215.10 Some Descriptor OperationsDescriptors and the Text ConsoleSymbian OS provides a text console class called CConsoleBase whichallows you to output formatted text to the screen and accept keyboardinput.
This can be useful when first experimenting with descriptors.The following code shows how a literal and stack descriptor can bedisplayed using CConsoleBase::Printf(). The code displays ‘HelloWorld!’ to the console twice, then pauses until the user presses a key.#include <e32base.h>#include <e32cons.h>TInt E32Main(){_LIT(KTxtConsoleTitle, "Hello Title");CConsoleBase* console = Console::NewL(KTxtConsoleTitle,TSize(KConsFullScreen, KConsFullScreen));_LIT(KTxtHelloWorld, "Hello World!\n");console->Printf(KTxtHelloWorld);TBufC<20> constantBuffer(KTxtHelloWorld);console->Printf(constantBuffer);console->Getch();delete console;return 0;}// get a input character from the userAny of the descriptor types can be passed directly to Printf() to bedisplayed.Printf() can also take a formatting string similar to the sprintf()method in standard C.
To display C-style strings, use %s as the formatter; todisplay descriptors, use %S. You must also pass the address of descriptorsas follows:TText array[] = L"Hello World!\n";TBufC<20> constantBuffer(KTxtHelloWorld);HBufC* hBuf = KTxtHelloWorld().AllocL();_LIT(KFormatTxt, "%s%S%S");console->Printf(KFormatTxt, array, &constantBuffer, hBuf);delete hBuf;This displays ‘Hello World’ three times. Note how the address ofconstantBuffer is passed as a parameter (leaving off the & wouldresult in an exception); but hBuf is already an address so prefixing with& is not necessary.122DESCRIPTORSThis same pattern of using %s for C-style strings and %S for descriptorstrings is used in several other places within Symbian OS where formattingfunctionality is used.CConsoleBase doesn’t have any input method other than Getch()which gets a single character at a time.
If you want to use it to get stringsfrom the console, you must construct a loop to suit your purposes:TBuf<20> buf;TKeyCode c = console->Getch();// TKeyCode is declared in e32keys.hwhile(c != EKeyEscape ){console->Printf(_L("%c"), c);buf.Append(c);// overflow checking omitted for clarityc = console->Getch();}Converting a Descriptor to a NumberThe contents of a descriptor can be converted into a number using theVal() method of the TLex class. For example:_LIT(KNumber, "12345");TLex lex(KNumber);TInt value = 0;User::LeaveIfError(lex.Val(value));// the number 12345 is assigned to valueThe Val() method has many overloads for conversion to differentnumerical types, with or without limit checking, including options forconversion from decimal, binary, octal, etc.