diff -r 43e37759235e -r 51a74ef9ed63 Symbian3/SDK/Source/GUID-4AC3CC42-6E8D-584A-AA39-84B5E0F3C16A.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/SDK/Source/GUID-4AC3CC42-6E8D-584A-AA39-84B5E0F3C16A.dita Wed Mar 31 11:11:55 2010 +0100 @@ -0,0 +1,349 @@ + + + + + +How to +use the resizable buffer descriptor - RBufUse this descriptor to hold a string or binary data. +

A resizable buffer descriptor is an RBuf type. Use the +member functions of the base classes: TDes and TDesC to +change the data in the descriptor. See Abstract +base descriptor classes.

+

This buffer of the descriptor is put on the heap. The buffer is the place +where the data is put. This is useful if you do not know the maximum size +of the data until run time.

+

The resizable buffer descriptors are similar to what are called Heap +descriptors, or HBufC types, but the API provided +by RBuf is easier to use. The RBuf API also +makes it easier to change the maximum size of the buffer containing the data, +a task often referred to as reallocating the buffer.

+

The general guidelines are: use HBufC descriptors to +contain data that rarely changes; use RBuf descriptors +to contain data that changes frequently. However, in practice, RBuf types +are equally suitable for both cases, and you should always consider using +an RBuf in preference to an HBufC.

+

For cases where your code uses APIs that return an HBufC type, +you can convert this to an RBuf. In effect, RBuf can +act as a wrapper around the HBufC; access and manipulation +of the data is then done through the member functions of RBuf and +its base classes TDes and TDesC

+

Some key points about resizable buffer descriptors:

+ +

Although the following notes refer to the build independent types, they +are equally valid for the explicit 8-bit and 16-bit types.

+ +
Creating an +RBuf

An RBuf object behaves like a handle to +a resource. In this case, the resource is the buffer that contains the data. +While this might seem to be an implementation issue, you need to understand +that much of the interface provided by the RBuf class itself +is involved in allocating, freeing and resizing this buffer.

An RBuf object +can:

    +
  • be placed on the program +stack.

  • +
  • be a member of another +'C' type class.

  • +

An RBuf object cannot be a member of a 'T' type +class.

See also Class +types.

The default constructor does not allocate a buffer, +and means that, by default, the object represents no data. In descriptor terminology, +its length is zero and its maximum length is zero.

Before an RBuf can +hold any data, you need to create the buffer.

    +
  • Simple construction

  • +
  • More advanced construction

  • +
  • Creating an RBuf from an existing descriptor

  • +
  • Creating an RBuf by transferring ownership of a pre-existing buffer

  • +

Simple construction

The +simplest way to create the buffer is to use the Create() or +the CreateL() member functions of RBuf [See RBuf16::Create() and RBuf16::CreateL()].

For example, the following code fragment constructs a resizable +buffer descriptor that can hold up to 15 data items. In descriptor terminology, +this means that the maximum length is set to 15. The current length of the +descriptor is set to zero, i.e. it contains no data.

RBuf buf; +... +buf.CreateL(15); +...

Note that CreateL() is similar to Create(), +but leaves if memory cannot be allocated.

More advanced construction

A +variation on the simple creation technique is to use the CreateMax() or +the CreateMaxL() member functions of RBuf [See RBuf16::Create() and RBuf16::CreateL()].

These functions not only allocate the buffer, but set the current +length of the data to be the same as the maximum length. For example:

RBuf buf; +... +buf.CreateMaxL(15); +...

No data has been assigned to the descriptor, and in effect +it contains "arbitrary" data. However, this can be useful in cases where the +descriptor needs to have a current length before calling another function. +For example, you might want a buffer of 16 bytes initialised to binary zeroes:

RBuf8 buf; +... +buf.CreateMaxL(15); +buf.Fillz(); +...

FillZ() provided by the TDes8 base +class, sets the data to binary zeroes for the length of the descriptor, 15 +bytes in this example. Note that we have explicitly used the 8-bit variant +here.

There are other ways of achieving this, but this is an economical +technique.

Creating an RBuf from an +existing descriptor

A common requirement is to create an RBuf and +to copy the data from an existing descriptor of any type. RBuf provides +variants of Create() and CreateL() to do +this.

In the following code fragment, a TBuf descriptor +is passed to a function, which then passes it to this CreateL() variant. +The source descriptor has a maximum length of 15, which means that the RBuf buffer +is allocated so that the RBuf maximum length is also 15.

The +content of the source descriptor is copied into the RBuf, +and the length of the RBuf (i.e. the length of data that +the descriptor represents) is set to be the same as that of the source descriptor +- in this case 11.

_LIT(KSampleText,"Hello World"); +... +TBuf<15> sampletext(KSampleText); +FuncL(sampletext); +... +void FuncL(TDesC& aSource) + { + RBuf buf; + + buf.CreateL(aSource); + ... + } +

The following code fragment constructs a resizable buffer +descriptor and copies data from a source descriptor. The length of data copied +is limited by the value of the second parameter. If this is less than the +length of the source descriptor, then only this length of data is copied. +The buffer allocated is large enough to contain data of length specified by +this second parameter.

This is often used in cases where the length +of the source data is not easily predictable, and it is important to limit +the size of the RBuf buffer created.

There are two +possibilities in this code fragment :

    +
  • if the length of aSource is +20, then the maximum length of buf is limited to 10, only +half the data in aSource is copied, and the length of buf is +set to 10.

  • +
  • if the length of aSource is +8, then the maximum length of buf is still set to 10; all +8 items are copied, and the length of buf is set to 8.

  • +
void FuncL(TDesC& aSource) + { + RBuf buf; + ... + buf.CreateL(aSource,10); + ... + } +

Creating an RBuf by transferring +ownership of a pre-existing buffer

An important technique is to +create an RBuf and transfer ownership of existing allocated +memory to it. This allows any data in that block of memory to be managed through +the RBuf.

There are three main cases to consider:

    +
  • transferring ownership +of a preexisting heap descriptor, an HBufC type.

  • +
  • transferring ownership +of allocated memory

  • +
  • transferring ownership +of the buffer owned by a different RBuf.

  • +

Transferring ownership +of an HBufC

This is a mechanism you would use if an existing API +returned an HBufC, and you wanted to deal with its data +through an RBuf instead.

The following code fragment +shows how this could be done. Note that the HBufC pointer +is passed to the RBuf constructor.

Following construction, +ownership of the heap descriptor has been passed to the RBuf object. +In descriptor terminology, the maximum length of the RBuf is +15, and its length is 11, reflecting the state of the original HBufC object.

You +can now manipulate any data that may have been assigned to the original HBufC, +through the functions in the RBuf base classes.

HBufC* hptr; +_LIT(KSampleText,"Hello World"); +... +hptr = HBufC::NewL(15); // Creates a heap descriptor which can hold up +... // to 15 data items. The current length is zero. +*hptr = KSampleText; // Assigns some data to the heap descriptor. +... // The current length of the heap descriptor is now 11. +RBuf buf(hptr); // Ownership of the heap descriptor is passed +... // to the RBuf during construction of the RBuf. +

There is an alternative technique that allows you to assign +ownership of the HBufC after construction of the RBuf using +the Assign() function. This allows you to reuse the same RBuf object. +For example:

HBufC* hptr; +_LIT(KSampleText,"Hello World"); +... +hptr = HBufC::NewL(15); // Creates a heap descriptor which can hold up +... // to 15 data items. The current length is zero. +*hptr = KSampleText; // Assigns some data to the heap descriptor. +... // The current length of the heap descriptor is now 11. +RBuf buf; +... +buf.Assign(hptr); // Ownership of the heap descriptor is passed +... // to the RBuf after construction of the RBuf. +

Once ownership has been transferred, you must not access the +data through the original HBufC pointer.

There is +no mechanism for reversing the transfer of ownership. The freeing of the buffer +can only be done through the RBuf. See Freeing the buffer.

Transferring +ownership of allocated memory

In the following code fragment, ptr is +assumed to contain the address of memory previously allocated. The code fragment +shows how ownership of this memory can be transferred to the RBuf.

TUint16* ptr; +TInt length(32); +... // Assume memory of length 32 has been allocated + // and its address stored in ptr. + +RBuf buf; +... +buf.Assign(ptr,length); +... // The memory passed to the descriptor becomes the + // descriptor's buffer. In descriptor terminology, + // the maximum length of the RBuf is 32; its length + // is zero, meaning that the descriptor represents + // no data. +

Transferring +ownership of the buffer owned by a different RBuf

In the following +code fragment, an RBuf is created, a buffer created for it, +and then ownership is transferred to another RBuf.

RBuf bufSource; +RBuf bufTarget; +... +bufSource.CreateL(15); // Creates memory buffer for the descriptor + // that can hold up to 15 data items. In descriptor + // terminology, the maximum length is set to 15 and + // the current length is set to 0. + +bufTarget.Assign(bufSource); // Transfers ownership of the memory buffer + // to the bufTarget descriptor. +...
+
Re-allocating +the memory buffer

You can change the size of the memory buffer, +by using the ReAlloc() or ReAllocL() member +functions of RBuf.

It does not matter how the original +buffer was allocated, whether directly via Create(), CreateL(), CreateMax() or CReateMaxL(), or by transfer of ownership of an existing buffer (and this includes transfer +from an HBufC). You do this if you intend to increase (or +significantly decrease) the amount of data that the descriptor is to represent. +Remember that the amount of memory allocated to the buffer is not automatically +changed in response to changes in the amount of data.

In the following +code fragment, an RBuf is created by copying from an existing +descriptor. It is then reallocated so that its maximum length is doubled. +Error conditions, such as out-of-memory conditions are ignored.

_LIT(KSampleText,"Hello World"); +... +TBuf<15> sampletext(KSampleText); +FuncL(sampletext); +... +void FuncL(TDesC& aSource) + { + RBuf buf; + Tint max; + + buf.CreateL(aSource); // max size is 15, length is 11. + max = buf.MaxLength() * 2; + buf.ReallocL(max); // max size is now 30, but length is still 11. + ... + } +
+
Freeing the +buffer

You can free the memory buffer by calling ReAlloc() or ReAllocL() and +passing a zero value.

_LIT(KSampleText,"Hello World"); +... +TBuf<15> sampletext(KSampleText); +FuncL(sampletext); +... +void FuncL(TDesC& aSource) + { + RBuf buf; + + buf.CreateL(aSource); // max size is 15, length is 11. + buf.ReallocL(0); // max size is now 0, length is 0, the memory + // buffer has been freed, and data + // has been thrown away. + ... + } +

You can also use the Close() member function +of RBuf. For example:

_LIT(KSampleText,"Hello World"); +... +TBuf<15> sampletext(KSampleText); +FuncL(sampletext); +... +void FuncL(TDesC& aSource) + { + RBuf buf; + + buf.CreateL(aSource); // max size is 15, length is 11. + buf.Close(); // max size is now 0, length is 0, the memory + // buffer has been freed, and data + // has been thrown away. + ... + } +
+
Cleanup rules
    +
  • To avoid memory leaks +when the RBuf object is placed on the stack, you should use +the following programming pattern:

    { +RBuf buf; +buf.CleanupClosePushL(); +... // Use the RBuf +CleanupStack::PopAndDestroy() //remove from cleanup stack + // and free the buffer to avoid memory +}

    The CleanupClosePushL() function puts a +cleanup item onto the cleanup stack. The effect of this is to cause the class's Close() function +to be called in the event of a leave occurring. In its turn, Close() simply +frees off the buffer.

  • +
  • If an RBuf is +a member of a class, then that class's destructor must remember to call either +: ReAllocL(0) or Close().

  • +
  • An RBuf can +be reused, but you must remember to call either : ReAllocL(0) or Close() before +you assign other memory or another HBufC. Failure to do this +will result in a memory leak.

  • +
  • You should not use an RBuf as +a member of a 'T' type class. See Class +types.

  • +
+
Replacing and +modifying data

Data in an RBuf descriptor can +be replaced. It can also be modified using the standard functionality provided +by the TDes base class.

_LIT(KSampleText,"Hello World"); +... +TBuf<15> sampletext(KSampleText); +FuncL(sampletext); +... +void FuncL(TDesC& aSource) + { + RBuf buf; + + buf.CreateL(aSource.MaxLength()); // Create the RBuf. + buf = aSource; // Copy "Hello World" using the assignment + // operator. + + buf.Delete(1,1); // Delete the 1st character. + ... + buf.Close(); + } +
+
\ No newline at end of file