Descriptorclasses can be classified according to where their data buffer is located:
• stack descriptor : data buffer is as part of themselves
• heap descriptor : data bufferis stored in the heap.
• pointer descriptor : does not own data buffer,
databuffer they pointed to can be anywhere.
TLitC and TPtrCare not modifiable at all, however TBufC and HBufC are not directly modifiable,but they are indirectly modifiable.
1. Literals
Literals areusually referred to as literal descriptors; because they are stored in the programbinary, they are also sometimes referred to as program binary descriptors. As programbinary is executed either directly from ROM or from read-only RAM, literals arealso read-only.
In standard C++,literal can be included in the program binary by declaring them as staticconstant:
static const charKTxtHelloWorld[] = "Hello World!";
In Symbian OS,literal is included in the program binary by using TLitC class, however younever actually use this class directly, instead you use it indirectly via themacro _LIT as follows:
_LIT(KTxtHelloWorld,"Hello World!");
The binary layoutof TLitC is designed to be identical to a TBufC, which allows TLitC to betreated as descriptor. Although literals aren’t actually descriptors, they canbe converted to descriptor by usingoperator()()method.
2. Stack Descriptors
3. Pointer Descriptors
All TPtrs aretype 2 unless they are created by using HBufC::Des() or TBufC::Des() methods.
Be aware that ifyou have more than one type 4 TPtr pointing to the same HBufC or TBufC, thenmodifications made via one are not reflected in the others.
4. Heap Descriptors
Heap descriptors havetheir data buffer created in the heap. With both RBuf and HBufC, if the heap buffersize needs to be expanded, it can not be done automatically, you must resize thedescriptor manually by using ReAlloc() or ReAllocL().
4.1 HBufC
The stackdescriptors, TBuf and TBufC, are templated, and the template value determinesthe length of the data area.
HBufC is slightlydifferent. To save memory, HBufC does not store its maximum length; instead, itfinds out its maximum length by finding out the size of the heap cell where itis stored.
Heap cells havedifferent granularity that depends on the specific hardware to which Symbian OShas been ported. When allocating memory, Symbian OS always rounds up to thenext nearest granularity boundary, so if you create HBufC with a specificlength, you may end up with a bigger descriptor than you asked for.
4.2 RBuf
All RBufs aretype 2 unless they take ownership of an existing HBufC by using constructorRBuf(HBufC *aHBuf) or Assign(HBufC16 *aHBuf).
Create() and Assign()orphans any data already owned by the RBuf, so Close() should be called whereappropriate to avoid memory leaks.
5. Descriptors as Parameters
• To pass a descriptor as an input parameter into a method (i.e., to pass descriptor datathat is read within the method but is not changed), use const TDesC&as the parameter type.
• To pass an in–out parameter to a method (i.e., to pass descriptor data that youwant to change within your method), use TDes& as the parameter type.
If you need tocreate a heap buffer within your method and pass ownership to the callingcode, then the choice is between an HBufC and an RBuf.
The standardpattern for creating an HBufC is to return it from the method.
HBufC*CSomeClass::GetSomeTextL()
{
HBufC* hBuf =iEikonEnv->AllocReadResourceL(someResourceID);
return hBuf;
}
HBufC* hBuf = GetSomeTextL();
. . .
delete hBuf;
Usually, if amethod needs to create an HBufC and pass ownership of it to thecaller this is done by returning it, however there may be circumstanceswhen something else must be returned from the method.
In thesecircumstances, this can be accomplished using a parameter instead:
TIntFooL(HBufC*& aBuf)
{
ASSERT(aBuf ==NULL);
aBuf =KTxtHelloWorld().AllocL();
return KErrNone;
}
HBufC* buf =NULL;
FooL(buf);
delete buf;
Note that if theHBufC needs to be created before being passed to a method andassigned within the method, then this can also be accomplishedusing an HBufC*& parameter, though if you need to use ReAlloc() withinthe method, then caution should be exercised (see Section 5.11).
If the heapdescriptor is not written to or is written to infrequently then use HBufC;however if the heap descriptor is to be written to frequently then an RBuf ispreferable as it is more efficient.
An RBuf cannot bereturned from a method as its copy constructor is protected,
voidcopyTextL(RBuf& aDes)
{
_LIT(KTxtHello,"Hello");
if(aDes.MaxLength() < KTxtHello().Length())
{
aDes.ReAllocL(KTxtHello().Length());
}
aDes = KTxtHello;
}
6. Correct Use of Descriptors
Do Not Declare TDesC or TDes Variables
TDesC and TDes donot contain any actual data, thus you should never instantiate TDesC or TDes.
_LIT(KTxtHelloWorld,"Hello World!");
// compile successfully,but neither hold the actual data
TDesdes(KTxtHelloWorld);
TDesCdesC(KTxtHelloWorld);
Always Pass TDes and TDesC Parameters by Reference
The reason isthat TDesC and TDes do not contain any actual data. If you pass them by value, thepolymorphism won’t work. The end result is that your code compiles but you are notactually passing any data.
Always Define const when Declaring TDesC Parameters
If omit the const keyword when declaring TDesC parameter, a compilation error maybe generated depending upon the compiler used. Even if no compilation errorgenerated for the function declaration, when calling this function and passinga literal to that parameter does lead to a compilation error.
Do Not Place Large Stack Descriptors on the Stack
A Symbian OS ruleof thumb is that if something is more than 256 bytes, then it shouldn’t go onthe stack (the stack size is pretty limited: the default is 8 KB). So, youshould consider using RBuf or HBufC instead.
It is advisableto be aware of the following types:
• TEntry consumes 552 bytes
• TFileName consumes 520 bytes
• TFullName consumes 520 bytes
• TName consumes 264 bytes.
Be Wary of HBufC::ReAllocL() and HBufC::ReAlloc()
The call toReAllocL() creates a new heap descriptor and, if successful, copies theoriginal data into it and returns the new address. The original copy is deleted.After reallocation, the new heap descriptor may be located in a different heapcell.
This is particularlyimportant if you use Des() method, in which case you need to re-Set() any TPtrreturned by Des().
Besides, you mustpay attention if you are pushing HBufC s to the cleanup, in which case you needto pop the original HBufC address off the stack, and re-push the new one.
Use _LIT Instead of _L
_LIT macro ismore efficient than _L. Although _L is deprecated, it is still acceptable to usebecause it doesn’t have to be declared separately:
User::Panic(_L("ServerPanic"), KPanicCode);
############# _Land _LIT are defined in e32def.h ##################
#ifdefined(_UNICODE)
#define _L(a)(TPtrC((const TText *)L ## a))
#define_LIT(name,s) static const TLitC<sizeof(L##s)/2>
name={sizeof(L##s)/2-1,L##s}
#else
#define _L(a)(TPtrC((const TText *)(a)))
#define_LIT(name,s) static const TLitC<sizeof(s)>
name={sizeof(s)-1,s}
#endif
Avoid Declaring Literals in Header Files
When usingliterals, try not to declare them in the header file because all CPP filesincluding it will generate a new copy, which can lead to code bloat.
Instead put _LITsin the CPP file.
Initialize TPtr Class Data Members
TPtr does nothave a default constructor, so when it is used as a data member of a class, itmust be initialized in the constructor’s initialization list, otherwise acompilation error will be generated.
#include <e32base.h>
#include <e32cons.h>
void HelloWorldL(void)
{
// Create a literal descriptor
_LIT(KTxtHelloWorld, "Hello World!");
const TInt KHelloWorldLength = 12;
// create aTBuf
TBuf<KHelloWorldLength> tbuf(KTxtHelloWorld);
// create a TBufC
TBufC<KHelloWorldLength> tbufc(KTxtHelloWorld);
// create an HBufC
HBufC* hbufc = KTxtHelloWorld().AllocLC();
// Create an RBuf
RBuf rbuf;
rbuf.CreateL(KHelloWorldLength, KTxtHelloWorld);
rbuf.CleanupClosePushL();
// create a TPtrC
TPtrC tptrc(tbufc);
// create a TPtr
TPtr tptr = hbufc->Des();
// display "Hello World!" 7 times to the text console
CConsoleBase* console = Console::NewL(KTxtHelloWorld, TSize(KConsFullScreen,KConsFullScreen));
console->Printf(KTxtHelloWorld);
console->Printf(tbuf);
console->Printf(tbufc);
console->Printf(tptr);
console->Printf(tptrc);
console->Printf(*hbufc);
console->Printf(rbuf);
console->Getch(); // pause until user enters input
CleanupStack::PopAndDestroy(2);
delete console;
}
GLDEF_C TInt E32Main()
{
static CTrapCleanup* cleanup = CTrapCleanup::New();
TRAPD(ret,HelloWorldL());
delete cleanup;
return (0);
}