BDE 4.14.0 Production release
|
Typedefs | |
typedef bslma::TestAllocatorMonitor | bslma_TestAllocatorMonitor |
This alias is defined for backward compatibility. | |
Provide a mechanism to summarize bslma::TestAllocator
object use.
bslma::TestAllocator
summary mechanismThis component provides a single mechanism class, bslma::TestAllocatorMonitor
, which is used, in concert with bslma::TestAllocator
, in the implementation of test drivers. The bslma::TestAllocatorMonitor
class provides boolean accessors indicating whether associated test allocator state has changed (or not) since construction of the monitor. Using bslma::TestAllocatorMonitor
objects often result in test cases that are more concise, easier to read, and less error prone than test cases that directly access the test allocator for state information.
The test allocator statistics tracked by the test allocator monitor along with the boolean accessors used to observe a change in those statistics are shown in the table below. The change (or lack of change) reported by these accessors are relative to the value of the test allocator statistic at the construction of the monitor. Note that each of these statistics count blocks of memory (i.e., number of allocations from the allocator), and do not depend on the number of bytes in those allocated blocks.
The numBlocksMax
and numBlocksTotal
statistics have values that are monotonically non-decreasing; hence, they need no "Is-Down" methods. Note that if a monitor is created for an allocator with outstanding blocks ("in
use"), then it is possible for the allocator's count of outstanding blocks to drop below the value seen by the monitor at construction.
This section illustrates intended use of this component.
Classes taking bslma::allocator
objects have many requirements (and thus, many testing concerns) that other classes do not. Here we illustrate how bslma::TestAllocatorMonitor
objects (in conjunction with bslma::TestAllocator
objects) can be used in a test driver to succinctly address many concerns of an object's use of allocators.
First, for a test subject, we introduce MyClass
, an unconstrained attribute class having a single, null-terminated ascii string attribute, description
. For the sake of brevity, MyClass
defines only a default constructor, a primary manipulator (the setDescription
method), and a basic accessor (the description
method). These suffice for the purposes of these example. Note that a proper attribute class would also implement value and copy constructors, operator==
, an accessor for the allocator, and other methods.
Notice that the implementation of the manipulator allocates/deallocates memory before updating the object. This ordering leaves the object unchanged in case the allocator throws an exception (part of the strong exception guarantee). This is an implementation detail, not a part of the contract (in this example).
Then, we design a test-driver for MyClass
. Our allocator-related concerns for MyClass
include:
Notice that some of these concerns (e.g., C-5..6) are not part of the class's documented, contractual behavior. These are classified as Quality of Implementation (QoI) concerns.
Next, we define a test plan. For example, a plan to test these concerns is:
The implementation of the plan is shown below:
Then, we implement the first portion of the plan. We create the trio of test allocators, their respective test allocator monitors, and install two of the allocators as the global and default allocators:
Then, we default construct a test object using the object allocator, and then, immediately destroy it. The object allocator monitor, oam
, shows that the allocator was not used.
Next, we pass the (still unused) object allocator to another test object. This time, we coerce the object into allocating memory by setting an attribute. (Setting an attribute larger than the receiving object means that the object cannot store the data within its own footprint and must allocate memory.)
Notice, as expected, memory was allocated from object allocator.
Now that the allocator has been used, we create a second monitor to capture the that state. Confirm that the basic accessor (the description
method) does not use the allocator.
Next, confirm that when a shorter value is assigned, the existing memory is reused.
Notice that there are no allocations because the object had sufficient capacity in previously allocated memory to store the short string.
Next, as an additional test, we make the object allocate additional memory by setting a longer attribute: one that exceeds the capacity allocated for DESCRIPTION1
. Use the second monitor to confirm that an allocation was performed.
There are tests where using a test allocator monitor does not suffice. Our test object is currently holding memory, if we assign a value that exceeds its current capacity there will be two operations on the object allocator: the allocation of larger memory, and the deallocation of its current memory: in that order, as part of the strong exception guarantee. Thus, the maximum number of allocations should go up by one, and no more.
Note that absence of memory leaks due to exceptions (the other part of the strong exception guarantee is confirmed during the destruction of the object test allocator at the end of this test, which featured exceptions.
Notice that our test allocator monitor cannot confirm that the allocator's maximum increased by exactly one. In this case, we must extract our statistics directly from the test allocator.
Note that increment in "max" occurs only the first time through the allocate/deallocate scenario in setDescription
.
Now, we close scope and check that all object memory was deallocated
Finally, we check that none of these operations used the default or global allocators.