Provide a guard to unconditionally manage a block of memory.
More...
Namespaces |
namespace | bslma |
Detailed Description
- Outline
-
-
- Purpose:
- Provide a guard to unconditionally manage a block of memory.
-
- Classes:
-
- See also:
- Component bslma_deallocatorproctor, Component bslma_autodeallocator
-
- Description:
- This component provides a guard class template,
bslma::DeallocatorGuard
, to unconditionally manage a block of (otherwise-unmanaged) memory. The managed memory is deallocated automatically when the guard object goes out of scope using the deallocate
method of the parameterized ALLOCATOR
(allocator or pool) supplied at construction.
-
- Requirement:
- The parameterized
ALLOCATOR
type of the bslma::DeallocatorGuard
class template must provide a (possibly virtual
) method: void deallocate(void *address);
to deallocate memory at the specified address
(originally supplied by the ALLOCATOR
object).
-
- Usage:
- A
bslma::DeallocatorGuard
can be used to ensure that a dynamically allocated raw memory resource is safely deallocated in the presence of multiple return statements or exceptions in an exception-neutral way (i.e., without the need for try
/catch
blocks). In this simple example, consider the function evaluatePassword
which attempts to determine how secure a given password might be: This function will be implemented in terms of three exception neutral subroutines, each of which operates on a writable copy of the null-terminated password, (perturbing its contents slightly) and requiring unbounded amounts of scratch memory (to be allocated and deallocated from a supplied allocator): A final subroutine is then used to determine and return the score: double finalSubroutine(const char *result);
The top-level routine is implemented as follows: double evaluatePassword(const char *password, bslma::Allocator *allocator)
{
size_t size = strlen(password) + 1;
char *buffer = (char *)allocator->allocate(size);
memcpy(buffer, password, size);
bslma::DeallocatorGuard<bslma::Allocator> guard(buffer, allocator);
if (0 != subroutine1(buffer, allocator)) {
return 0.0;
}
if (0 != subroutine2(buffer, allocator)) {
return 0.2;
}
if (0 != subroutine3(buffer, allocator)) {
return 0.4;
}
return finalSubroutine(buffer);
}
Notice that if any of the initial (numbered) subroutines returns a non-zero status value, the top-level evaluatePassword
routine returns immediately with a predetermined score. Moreover, each of these routines may encounter a bad_alloc
exception should the supplied allocator fail to return the requested memory. Even if all of these subroutines evaluates successfully, the score calculated using finalEval
is returned directly by evaluatePassword
, yet we still need to deallocate buffer
. By guarding buffer with a bslma::DeallocatorGuard
as shown above, all of these issues are fully addressed, and the top-level routine is also exception neutral as desired.