Memory Management in RWBasicUString
In typical usage, an
RWBasicUString instance owns and manages the memory required to hold an array of
RWUChar16 values. Like
RWCString,
RWBasicUString normally copies input data to an internal buffer. This usage is both safe and convenient.
In some cases, however, such as constant strings or large strings, it may be more efficient to avoid this initial copy by having
RWBasicUString use an externally-supplied buffer. Therefore,
RWBasicUString can also be constructed with two alternate memory management strategies:
• An
RWBasicUString instance can reference an external buffer in a read-only fashion. In this case, a client supplies the constructor with a
Duration value of
Persistent. Any attempt to modify the external buffer causes
RWBasicUString to copy its contents to an internal buffer. This strategy is primarily used to treat static arrays or arrays of some other long storage duration as
RWBasicUString instances. For example:
// At file scope
static RWUChar16 acronym = [ 0x0052, 0x0057, 0x0000 ];
RWBasicUString
getAcronymAsUString()
{
return RWBasicUString(acronym, RWBasicUString::Persistent);
}
• An
RWBasicUString instance can assume ownership of an external buffer, and use it in a read-write fashion. To pass ownership of a buffer to an
RWBasicUString, a client supplies the
RWBasicUString constructor with an
RWBasicUString::Deallocator object that can be used to deallocate the buffer. (See
“Creating and Using Deallocators”.) This strategy is reminiscent of that offered by
std::auto_ptr<T>, except that
RWBasicUString implements copy construction and assignment via reference counting. An
RWBasicUString mutator modifies the external buffer directly if its capacity is large enough. Otherwise, the mutator copies the buffer's contents to an internal buffer, deallocates the external buffer, then modifies the internal buffer.
Note that in both cases, although the client’s choice of constructor determines the initial memory management strategy,
RWBasicUString will abandon an externally-supplied buffer in favor of an internal buffer as necessary.
Creating and Using Deallocators
Passing ownership of a buffer to an
RWBasicUString involves supplying the
RWBasicUString with an
RWBasicUString::Deallocator object.
RWBasicUString::Deallocator is an abstract base class that cannot be instantiated directly. Instead, a deallocator can be created in one of two ways:
An
RWBasicUString::StaticDeallocator object wraps a pointer to a class static method or a global function. As a convenience,
RWBasicUString supplies three such functions:
USE_DELETE(),
USE_FREE(), and
USE_NONE(). For example, the following code creates an
RWBasicUString::StaticDeallocator that invokes
delete[] to deallocate string buffers. These buffers are returned from a third-party library that allocates buffers via
new:
// Create a deallocator. It will be re-used by multiple
// RWBasicUString instances.
RWBasicUString::StaticDeallocator
deallocator(RWBasicUString::USE_DELETE);
// Return RWBasicUStrings that reference externally-supplied
// buffers.
RWBasicUString
getStringFromOutsideSource()
{
RWUChar16 *array = callToOutsideSource();
return RWBasicUString(array, &deallocator);
}
• Create an instance of a custom
RWBasicUString::Deallocator subclass.
The subclass can deallocate string buffers in the manner of its choice, to match the manner in which the buffers are allocated.
The use of
RWBasicUString::StaticDeallocator allows the client to choose
delete[],
free(), or custom memory-management mechanisms. The use of an externally supplied deallocation method can also be used to satisfy the heap management requirements of MS-Windows dynamic linked libraries, which in some situations may create their own heap in addition to that of the calling process.
Null Termination
Given sufficient capacity,
RWBasicUString adds a null terminator to any non-static array passed to it. This terminating null is not considered part of the contents, and is not included in the count returned by
length().