Sunday, June 26, 2005

33. Can you give an example of how to use RBuf?

Yes. I was initially reluctant to do so, because there isn't any published example code out there yet. But I'll take the plunge with this example, which shows how to use RBuf16. I'll leave code to use RBuf8, and to use the non-leaving Create() methods as an exercise for the reader, for now.

void ExampleRBufCodeL()
{

__UHEAP_MARK;

// RBuf::CreateL
RBuf modifiableBuf;
modifiableBuf.CreateL(12);
ASSERT(modifiableBuf.Length()==0);
ASSERT(modifiableBuf.MaxLength()==12);
... // Do stuff. First push modifiableBuf onto the cleanup stack if a leave may occur
modifiableBuf.Close();

// RBuf::CreateMaxL
modifiableBuf.CreateMaxL(12);
ASSERT(modifiableBuf.Length()==12);
ASSERT(modifiableBuf.MaxLength()==12);
... // Do stuff. First push modifiableBuf onto the cleanup stack if a leave may occur
modifiableBuf.Close();

// RBuf::CreateL passing in a descriptor
_LIT(KHelloWorld, "Hello World");
modifiableBuf.CreateL(KHelloWorld());
ASSERT(modifiableBuf.Length()==11);
ASSERT(modifiableBuf.MaxLength()==11);
... // Do stuff. First push modifiableBuf onto the cleanup stack if a leave may occur
modifiableBuf.Close();

// RBuf::CreateL passing in a descriptor and a maximum length
modifiableBuf.CreateL(KHelloWorld(), 15);
ASSERT(modifiableBuf.Length()==11);
ASSERT(modifiableBuf.MaxLength()==15);
... // Do stuff. First push modifiableBuf onto the cleanup stack if a leave may occur
modifiableBuf.Close()

// RBuf::CreateL and ReAllocL & modifiable descriptor base class methods
_LIT(KHello, "Hello");
_LIT(KWorld, " World");
modifiableBuf.CreateL(5);
modifiableBuf.Copy(KHello());
modifiableBuf.CleanupClosePushL(); // Push onto cleanup stack for leave safety
modifiableBuf.ReAllocL(11);
modifiableBuf.Append(KWorld);
CleanupStack::PopAndDestroy(); // Calls modifiableBuf.Close()

// RBuf::Assign
HBufC* hBuf = KHello().AllocL();
modifiableBuf.Assign(hBuf);
ASSERT(modifiableBuf.Length()==5);
... // Do stuff. First push modifiableBuf onto the cleanup stack if a leave may occur
modifiableBuf.Close();

// RBuf::Assign, ReAllocL and use of TDes::Append
TUint16* ptr = static_cast(User::AllocL(5*sizeof(TText)));
modifiableBuf.Assign(ptr,5);
ASSERT(modifiableBuf.Length()==0);
modifiableBuf.Copy(KHello()); // Copying any more would panic
modifiableBuf.CleanupClosePushL(); // Push onto cleanup stack for leave safety
modifiableBuf.ReAllocL(12);
modifiableBuf.Append(KWorld);
CleanupStack::PopAndDestroy(); // Calls modifiableBuf.Close()

__UHEAP_MARKEND;
}

Comments:
You should make your examples Leave-safe - I know that use of the Cleanup Stack may confuse the issue, but people may copy these examples verbatim.
 
Absolutely.

It wasn't a case of me trying not to confuse people with the cleanup stack. I very negligently wrote the code without due care and attention to leave safety. I've updated the example - many thanks for pointing it out.
 
What about using RBufs as return types from functions where previously you would have returned a HBufC*? Is there anything special to do? Should they be returned by value/reference etc.?
 
An interesting question. I took at look at what the Symbian headers do.

It seems to me that where a function would previously have returned ownership of a dynamic descriptor by returning an HBufC*, it should now take an "out" RBuf& parameter, which it uses to pass back the buffer.

I must admit that I've not used RBuf in this context, so can only go on what the experts do :o)
 
Its possible to return an RBuf& from a function, but of course if its referring to a stack variable it'll explode quicker than a very fat man who's eaten a dozen cabbages and 14 curries, but is ok if its referring to a data member.
 
Nice image. Though you forgot the wafer thin mint...

Yes. You're right.

This question has also been asked here, with some more information added...

http://discussion.forum.nokia.com/forum/showthread.php?t=84863&highlight=rbuf
 
As for the curries and cabbage - I now have more information from the BBC:
http://news.bbc.co.uk/2/hi/south_asia/5213238.stm
 
RBuf is also the best choice when reading strings from file. Using RBuf instead of HBufC requires less code. Also, error handling becomes more simpler.

Here is simple example how to read from RReadStream.
in .h: RBuf iSomeSetting;
in .cpp: iSomeSetting.CreateL( stream, KMaxTInt );

the HBufC would be:
iSomeSetting = HBufC::NewL( stream, KMaxTInt );
TPtr tmp( iSomeSetting->Des() );
stream >> tmp;

Getting the error situations handled with HBufC is much more trickier (not shown in example). However, with RBuf your all set, no need to check if the pointer is null etc.
 
Thanks Simo. I'm going to copy your comment to a separate post, since I'm sure other readers will find it useful.

Jo
 
Should
modifiableBuf.CreateL(5);
modifiableBuf.Copy(KHello());
modifiableBuf.CleanupClosePushL();

be:
modifiableBuf.CleanupClosePushL(); modifiableBuf.CreateL(5);
modifiableBuf.Copy(KHello());
 
Hi Tym

I don't think so - why?
The sequence CreateL(), Copy() and CleanupClosePushL() is safe because CleanupClosePushL() won't orphan modifiableBuf if it leaves (standard cleanup stack behaviour is to secure the pointer pushed first and only then do anything that may cause a leave).

It's also standard Symbian OS idiom to initialize something and then push it, rather than push and initialize.

But maybe I've misunderstood your comment?_L("")
 
I was surprised to discover that something as trivial as returning a pointer in c/c++ was not so easy to do in Symbian.
After i tried something like

TInt myFcn(const TDesC& input, HBufC& * output)

and failed i put together the following:

HBufC* testReturn(TUint count)
{
HBufC* returnDescriptor = HBufC::NewL(count);
TPtr16 ptr( returnDescriptor->Des() );
for(int i=0; i< count; i++)
ptr.Append( '0' + (i%10) );
return returnDescriptor;
}

void testReturn1(TUint count, RBuf& returnDescriptor)
{
returnDescriptor.Create(count);
for(int i=0; i< count; i++)
returnDescriptor.Append('0'+(i%10));
}

tested with:

HBufC* var1;
var1 = testReturn(3);
logger->writeFormatL(_L("first string %S length %d\n"), var1, var1->Length());
delete var1;

RBuf var2;
testReturn1(13, var2);
logger->writeFormatL(_L("second string %S length %d\n"), &var2, var2.Length());
var2.Close();

where logger is an instance of my custom logger with methods like
writeFormatL(TRefByValue< const TDesC16 > aFmt, ...);

Hope this helps
kenny
 
Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?

Google
WWW Descriptors FAQ