Outline
Purpose
Release memory to a managed allocator or pool at destruction.
Classes
- See also
- bslma_deallocatorproctor, bdlma_managedallocator
Description
This component provides a proctor object, bdlma::AutoReleaser
, to manage memory allocated from a managed allocator or pool. The proctor's destructor invokes the release
method of its managed allocator or pool unless the proctor's own release
method has been called. Note that after a proctor releases management of its managed allocator or pool, the proctor can be reused by invoking its reset
method with another allocator or pool object (of the same (template parameter) type ALLOCATOR
).
Requirements
The object of the (template parameter) type ALLOCATOR
must provide a method having the following signature:
Usage
This section illustrates intended use of this component.
Example 1: Using a bdlma::AutoReleaser to Preserve Exception Neutrality
A bdlma::AutoReleaser
proctor is often used to preserve exception neutrality for containers that allocate their elements using a managed allocator or pool. For operations that may potentially throw an exception, a proctor can be used to (temporarily) manage the container's allocator or pool and its associated memory. If an exception is thrown, the proctor's destructor invokes the release
method of its held allocator or pool, deallocating memory for all of the container's elements, thereby preventing a memory leak and restoring the container to the empty state.
In this example, we illustrate use of a bdlma::AutoReleaser
proctor within the operator=
method of my_FastStrArray
, a class that implements an array of C string elements. Note that a my_FastStrArray
object allocates memory for its C string elements using a string pool, my_StrPool
, the definition of which is elided.
First, we define the interface of our my_FastStrArray
class:
class my_FastCstrArray {
char **d_array_p;
int d_capacity;
int d_length;
my_StrPool d_strPool;
private:
void increaseSize();
my_FastCstrArray(const my_FastCstrArray&);
public:
~my_FastCstrArray();
my_FastCstrArray& operator=(const my_FastCstrArray& rhs);
void append(const char *item);
const char *operator[](int index) const { return d_array_p[index]; }
int length() const { return d_length; }
};
ostream&
operator<<(ostream& stream,
const my_FastCstrArray& array);
Definition bslma_allocator.h:457
bsl::ostream & operator<<(bsl::ostream &stream, const bdlat_AttributeInfo &attributeInfo)
Then, we implement the methods:
enum {
k_MY_INITIAL_SIZE = 1,
k_MY_GROW_FACTOR = 2
};
static inline
int nextSize(int size)
{
return size * k_MY_GROW_FACTOR;
}
static inline
void reallocate(char ***array,
int *size,
int newSize,
int length,
{
ASSERT(array);
ASSERT(*array);
ASSERT(size);
ASSERT(1 <= newSize);
ASSERT(0 <= length);
ASSERT(length <= *size);
ASSERT(length <= newSize);
char **tmp = *array;
*array = (
char **)allocator->
allocate(newSize *
sizeof **array);
bsl::memcpy(*array, tmp, length * sizeof **array);
}
void my_FastCstrArray::increaseSize()
{
reallocate(&d_array_p,
&d_capacity,
nextSize(d_capacity),
d_length,
d_allocator_p);
}
: d_capacity(k_MY_INITIAL_SIZE)
, d_length(0)
, d_allocator_p(
bslma::Default::allocator(basicAllocator))
{
d_array_p = (char **)d_allocator_p->allocate(
d_capacity * sizeof *d_array_p);
}
my_FastCstrArray::~my_FastCstrArray()
{
ASSERT(1 <= d_capacity);
ASSERT(0 <= d_length);
ASSERT(d_length <= d_capacity);
d_allocator_p->deallocate(d_array_p);
}
virtual void deallocate(void *address)=0
virtual void * allocate(size_type size)=0
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
Definition balxml_encoderoptions.h:68
Now, we implement my_FastCstrArray::operator=
using a bdlma::AutoReleaser
proctor to preserve exception neutrality:
my_FastCstrArray&
my_FastCstrArray::operator=(const my_FastCstrArray& rhs)
{
if (&rhs != this) {
d_strPool.release();
d_length = 0;
if (rhs.d_length > d_capacity) {
char **tmp = d_array_p;
d_array_p = (char **)d_allocator_p->allocate(
rhs.d_length * sizeof *d_array_p);
d_capacity = rhs.d_length;
d_allocator_p->deallocate(tmp);
}
for (int i = 0; i < rhs.d_length; ++i) {
const int size =
static_cast<int>(bsl::strlen(rhs.d_array_p[i])) + 1;
d_array_p[i] = (char *)d_strPool.allocate(size);
bsl::memcpy(d_array_p[i], rhs.d_array_p[i], size);
}
d_length = rhs.d_length;
autoReleaser.release();
}
return *this;
}
Definition bdlma_autoreleaser.h:288
Note that a bdlma::AutoReleaser
proctor is used to manage the array's C string memory pool while allocating memory for the individual elements. If an exception is thrown during the for
loop, the proctor's destructor releases memory for all elements allocated through the pool, thus ensuring that no memory is leaked.
Finally, we complete the implementation:
void my_FastCstrArray::append(const char *item)
{
if (d_length >= d_capacity) {
this->increaseSize();
}
const int sSize = static_cast<int>(bsl::strlen(item)) + 1;
char *elem = (char *)d_strPool.allocate(sSize);
bsl::memcpy(elem, item, sSize * sizeof *item);
d_array_p[d_length] = elem;
++d_length;
}
ostream&
operator<<(ostream& stream,
const my_FastCstrArray& array)
{
stream << "[ ";
for (int i = 0; i < array.length(); ++i) {
stream << '"' << array[i] << "\" ";
}
return stream << ']' << flush;
}