Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslma_deallocatorguard
[Package bslma]

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:
bslma::DeallocatorGuard guard to unconditionally manage a block of memory
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:
  double evaluatePassword(const char *password, bslma::Allocator *allocator);
      // Evaluate the strength of the specified 'password', using the
      // specified 'allocator' to supply memory for evaluation.  Return a
      // real value in the range '[ 0.0 .. 1.0 ]' where 0.0 indicates the
      // weakest password, and 1.0 the strongest.
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):
  int subroutine1(char *inOut, bslma::Allocator *allocator);
  int subroutine2(char *inOut, bslma::Allocator *allocator);
  int subroutine3(char *inOut, bslma::Allocator *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)
  {

      // Set up local writable copy of password in buffer.

      size_t size = strlen(password) + 1;
      char *buffer = (char *)allocator->allocate(size);
      memcpy(buffer, password, size);

      //**************************************************************
      //* Note the use of the deallocator guard on 'buffer' (below). *
      //**************************************************************

      bslma::DeallocatorGuard<bslma::Allocator> guard(buffer, allocator);

      // Process and evaluate the supplied password.

      if (0 != subroutine1(buffer, allocator)) {
          return 0.0;                                               // RETURN
      }
      if (0 != subroutine2(buffer, allocator)) {
          return 0.2;                                               // RETURN
      }
      if (0 != subroutine3(buffer, allocator)) {
          return 0.4;                                               // RETURN
      }

      return finalSubroutine(buffer);

  }  // note that 'buffer' is deallocated at end of block regardless
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.