Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslma_testallocatorexception
[Package bslma]

Provide an exception class for memory allocation operations. More...

Namespaces

namespace  bslma

Detailed Description

Outline
Purpose:
Provide an exception class for memory allocation operations.
Classes:
bslma::TestAllocatorException exception containing allocation information
Description:
This component defines a simple exception object for testing exceptions during memory allocation operations. The exception object bslma::TestAllocatorException contains information about the allocation request, which can be queried for by the "catcher" of this exception.
Usage:
In the following example, the bslma::TestAllocatorException object is thrown by the allocate method of the my_Allocator object after the number of allocation requests exceeds the allocator's allocation limit. This example demonstrates how to use a user-defined allocator (e.g., my_Allocator) and bslma::TestAllocatorException to verify that an object (e.g., my_ShortArray) under test is exception-neutral:
  // my_allocator.h
  #include <bslma_allocator.h>

  class my_Allocator : public bslma::Allocator {
      int d_allocationLimit;
      // ...

    private:
      // NOT IMPLEMENTED
      my_Allocator(const my_Allocator&);
      my_Allocator& operator=(const my_Allocator&);

    public:
      // CREATORS
      my_Allocator() : d_allocationLimit(-1) {}
      ~my_Allocator() {}

      void *allocate(int size);
      void deallocate(void *address) { free(address); }
      void setAllocationLimit(int limit){ d_allocationLimit = limit; }
      int allocationLimit() const { return d_allocationLimit; }
      // ...
  };

  // my_allocator.cpp
  #include <my_allocator.h>

  void *my_Allocator::allocate(int size)
  {
  #ifdef BDE_BUILD_TARGET_EXC
      if (0 <= d_allocationLimit) {
          --d_allocationLimit;
          if (0 > d_allocationLimit) {
              throw bslma::TestAllocatorException(size);
          }
      }
  #endif
      return (void *)malloc(size);
  }
Note that the macro BDE_BUILD_TARGET_EXC is defined at compile-time to indicate whether exceptions are enabled. In the above code, if exceptions are not enabled, the code that throws bslma::TestAllocatorException is never executed. The following is the test driver for my_ShortArray.
Note that "\$" must be replaced by "\" in the preprocessor macro definitions that follow. The "$" symbols are present in this header file to avoid a diagnostic elicited by some compilers (e.g., "warning: multi-line comment").
  // my_shortarray.t.cpp
  #include <my_shortarray.h>
  #include <my_testallocator.h>
  #include <bslma_testallocatorexception.h>

  // ...

  #ifdef BDE_BUILD_TARGET_EXC
  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN {                       \$
  {                                                                        \$
      static int firstTime = 1;                                            \$
      if (veryVerbose && firstTime) std::cout <<                           \$
          "### BSLMA EXCEPTION TEST -- (ENABLED) --" << std::endl;         \$
      firstTime = 0;                                                       \$
  }                                                                        \$
  if (veryVeryVerbose) std::cout <<                                        \$
      "### Begin bslma exception test." << std::endl;                      \$
  int bslmaExceptionCounter = 0;                                           \$
  static int bslmaExceptionLimit = 100;                                    \$
  testAllocator.setAllocationLimit(bslmaExceptionCounter);                 \$
  do {                                                                     \$
      try {

  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END                           \$
      } catch (bslma::TestAllocatorException& e) {                         \$
          if (veryVerbose && bslmaExceptionLimit || veryVeryVerbose) {     \$
              --bslmaExceptionLimit;                                       \$
              std::cout << "(*** " << bslmaExceptionCounter << ')';        \$
              if (veryVeryVerbose) { std::cout << " BSLMA_EXCEPTION: "     \$
                  << "alloc limit = " << bslmaExceptionCounter << ", "     \$
                  << "last alloc size = " << e.numBytes();                 \$
              }                                                            \$
              else if (0 == bslmaExceptionLimit) {                         \$
                  std::cout << " [ Note: 'bslmaExceptionLimit' reached. ]";\$
              }                                                            \$
              std::cout << std::endl;                                      \$
          }                                                                \$
          testAllocator.setAllocationLimit(++bslmaExceptionCounter);       \$
          continue;                                                        \$
      }                                                                    \$
      testAllocator.setAllocationLimit(-1);                                \$
      break;                                                               \$
  } while (1);                                                             \$
  if (veryVeryVerbose) std::cout <<                                        \$
      "### End bslma exception test." << std::endl;                        \$
  }
  #else
  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN                         \$
  {                                                                        \$
      static int firstTime = 1;                                            \$
      if (verbose && firstTime) { std::cout <<                             \$
          "### BSLMA EXCEPTION TEST -- (NOT ENABLED) --" << std::endl;     \$
          firstTime = 0;                                                   \$
      }                                                                    \$
  }
  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
  #endif

  // ...

  static
  bool areEqual(const short *array1, const short *array2, int numElement)
      // Return 'true' if the specified initial 'numElement' in the specified
      // 'array1' and 'array2' have the same values, and 'false' otherwise.
  {
      for (int i = 0; i < numElement; ++i) {
          if (array1[i] != array2[i]) return false;
      }
      return true;
  }

  int main(int argc, char *argv[]) {
      int test = argc > 1 ? atoi(argv[1]) : 0;
      int verbose = argc > 2;
      int veryVerbose = argc > 3;
      int veryVeryVerbose = argc > 4;

      my_Allocator testAllocator;

      switch (test) { case 0:

        // ...

        case 6: {
          struct {
              int d_line;
              int d_numElem;
              short d_exp[NUM_VALUES];
          } DATA[] = {
              { L_, 0, {} },
              { L_, 1, { V0 } },
              { L_, 5, { V0, V1, V2, V3, V4 } }
          };

          const int NUM_TEST = sizeof DATA / sizeof *DATA;

          for (int ti = 0; ti < NUM_TEST; ++ti) {
              const int    LINE     = DATA[ti].d_line;
              const int    NUM_ELEM = DATA[ti].d_numElem;
              const short *EXP      = DATA[ti].d_exp;

              BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN {
                  my_ShortArray mA(&testAllocator);
                  const my_ShortArray& A = mA;
                  for (int ei = 0; ei < NUM_ELEM; ++ei) {
                      mA.append(VALUES[ei]);
                  }
                  if (veryVerbose) { P_(ti); P_(NUM_ELEM); P(A); }
                  LOOP2_ASSERT(LINE, ti, areEqual(EXP, A, NUM_ELEM));
              } BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
          }

          if (veryVerbose) std::cout << testAllocator << std::endl;
        } break;

        // ...

      }

      // ...
  }