Outline
Purpose
Provide a wrapper for STL allocators, for container use.
Classes
- See also
- bslma_bslallocator
Description
This component provides a single mechanism class, bslalg::ContainerBase
, that can used as a base class by STL-style containers for storing the container's allocator. If instantiated with an empty allocator type, ContainerBase
will itself be an empty class type. Thus, a container class derived from ContainerBase
can benefit from the base-class optimization in that an empty allocator object will not add to the size of the container's footprint.
Usage
This section illustrates intended use of this component.
Example 1: Creating a Fixed-Size Array with bslalg::ContainerBase
Suppose we would like to implement a fixed-size array that allocates memory from a user-supplied allocator at construction.
First, we define the interface of the container, MyFixedSizeArray
. We privately derive from ContainerBase
to take advantage of the empty-base-class optimization (in case ALLOCATOR
is an empty class) and to take advantage of implementation conveniences ContainerBase
provides:
template <class VALUE, class ALLOCATOR>
{
VALUE *d_array;
const int d_size;
public:
typedef ALLOCATOR allocator_type;
explicit MyFixedSizeArray(int size,
const ALLOCATOR& allocator = ALLOCATOR());
MyFixedSizeArray(const MyFixedSizeArray& original,
const ALLOCATOR& allocator = ALLOCATOR());
~MyFixedSizeArray();
VALUE& operator[](int i) { return d_array[i]; }
const VALUE& operator[](int i) const { return d_array[i]; }
ALLOCATOR get_allocator() const;
int size()
const {
return d_size; }
};
Definition bslalg_containerbase.h:386
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
Next, we define the get_allocator accessor, which extracts the allocator from the ContainerBase
base class using its allocatorRef
method:
template<class VALUE, class ALLOCATOR>
inline
ALLOCATOR
MyFixedSizeArray<VALUE,ALLOCATOR>::get_allocator() const {
return Base::allocatorRef();
}
Next, we define the first constructor, beginning with the initialization the ContainerBase
base class with the supplied allocator
:
template<class VALUE, class ALLOCATOR>
MyFixedSizeArray<VALUE,ALLOCATOR>::MyFixedSizeArray(
int size,
const ALLOCATOR& allocator)
: Base(allocator)
, d_size(size)
{
Then, we allocate the specified number of array elements using the allocator returned by the get_allocator()
method. Once allocated, we protect the array memory with a bslma::DeallocateObjectProctor
object:
d_array =
bslma::AllocatorUtil::allocateObject<VALUE>(get_allocator(),
d_size);
deallocateProctor(get_allocator(), d_array, d_size);
Definition bslma_deallocateobjectproctor.h:273
Then, we invoke the constructor for each array element using the bslma::ConstructionUtil::construct
method. We use a bslma::AutoDestuctor
proctor to unwind these constructions if an exception is thrown:
for (int i = 0; i < d_size; ++i) {
++autoDtor;
}
Definition bslma_autodestructor.h:283
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator)
Definition bslma_constructionutil.h:1243
Then, when every element has been constructed, we free the proctors:
autoDtor.release();
deallocateProctor.release();
}
Next we implement the destructor as the reverse of the constructor, invoking bslma::DestructionUtil::destroy
on each element then deallocating them with bslma::AllocatorUtil::deallocateObject
:
template<class VALUE, class ALLOCATOR>
MyFixedSizeArray<VALUE,ALLOCATOR>::~MyFixedSizeArray()
{
for (int i = 0; i < d_size; ++i) {
bslma::DestructionUtil::destroy(&d_array[i]);
}
d_array, d_size);
}
static void deallocateObject(const t_ALLOCATOR &allocator, t_POINTER p, std::size_t n=1)
Definition bslma_allocatorutil.h:926
Next, for testing purposes, we create a StatelessAllocator
template that simply allocates a global test allocator:
template <class TYPE>
class StatelessAllocator {
public:
typedef TYPE value_type;
value_type *allocate(std::size_t n, void * = 0) {
return bslma::AllocatorUtil::allocateObject<value_type>(
&g_testAllocator, n);
}
void deallocate(value_type *p, std::size_t n) {
}
};
Definition bslma_testallocator.h:384
Finally, we create two MyFixedSizeArray
objects, one using StatelessAllocator
, and the other using bsl::allocator
, and we verify that memory is allocated from the correct allocator for each. Because StatelessAllocator
is an empty class, the first object is smaller than the second object by at least the size of a bsl::allocator
.
int main()
{
MyFixedSizeArray<int, StatelessAllocator<int> > fixedArray1(3);
assert(3 == fixedArray1.size());
MyFixedSizeArray<int, bsl::allocator<int> > fixedArray2(3, &ta);
assert(3 == fixedArray2.size());
assert(&ta == fixedArray2.get_allocator());
assert(sizeof(fixedArray2) - sizeof(fixedArray1) >=
}
Definition bslma_bslallocator.h:580
bsls::Types::Int64 numBlocksInUse() const
Definition bslma_testallocator.h:1087
bsls::Types::Int64 numBytesInUse() const
Definition bslma_testallocator.h:1111
Definition bslmf_isempty.h:315