BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdld_manageddatum

Detailed Description

Outline

Purpose

Provide a smart-pointer-like manager for a Datum object.

Classes

See also
bdld_datum

Description

This component implements a type, bdld::ManagedDatum, that provides two important services for Datum objects:

  1. ManagedDatum provides value-semantic-like operations for Datum.
  2. ManagedDatum is a resource manager, similar to a smart pointer, for Datum.

These services allow clients to use a ManagedDatum object in most contexts where an object of a value-semantic type can be used (passed by value, stored in containers, and so on), even though ManagedDatum is not strictly value-semantic. These services are explored in subsequent sections.

The Datum type maintained by a ManagedDatum provides a space-efficient discriminated union (i.e., a variant) holding the value of a scalar type (e.g., int, double, string) or an aggregate of other Datum objects. See bdld_datum for more details.

Value Semantics

ManagedDatum, while not strictly a value-semantic type, provides the full set of value-semantic-like operations for Datum (see Value-Semantic Operations [VS.1] :

In other words, the syntax of ManagedDatum is regular, but not all of its copy behavior is value-semantic. Specifically, for User Defined Types (i.e., those that bdld::Datum::clone does not deep-copy) ManagedDatum performs a shallow copy (copying the reference rather than the value), which is inconsistent with value-semantics. For all other types ManagedDatum copy operations (copy construction, copy assignment, and non-member swap when the allocators differ) will deep-copy the value using Datum::clone, which creates a completely independent copy, with independent lifetime, by duplicating all data, even referenced data (except for UDTs).

Note that a default constructed ManagedDatum, or a ManagedDatum on which release has been called, will have the null Datum value.

Resource Management

A Datum object's relationship to memory can be seen as analogous to a raw pointer, requiring calls to static functions Datum::create* and Datum::destroy to initialize and release resources (see the bdld_datum component documentation). A ManagedDatum, by extension, provides a resource manager for a Datum that is analogous to a smart pointer.

The adopt method of a ManagedDatum is used to take ownership of a supplied Datum object, after which point the ManagedDatum object's destructor will free the resources of the managed Datum (unless release is subsequently called). Similar to a smart pointer, a ManagedDatum provides dereference operators to access the Datum object under management.

Usage

This section illustrates intended use of this component.

Example 1: Basic Use of bdld::ManagedDatum

This example demonstrates the basic construction and manipulation of a ManagedDatum object.

First, we create a ManagedDatum object that manages a Datum holding a double and verify that the managed object has the expected type and value:

bslma::TestAllocator ta("test", veryVeryVerbose);
const ManagedDatum realObj(Datum::createDouble(-3.4375), &ta);
assert(realObj->isDouble());
assert(-3.4375 == realObj->theDouble());
Definition bslma_testallocator.h:384

Next, we create a ManagedDatum object that holds a string and again verify that it has the expected type and value:

const char *str = "This is a string";
const ManagedDatum strObj(Datum::copyString(str, &ta), &ta);
assert(strObj->isString());
assert(str == strObj->theString());

Then, we assign this ManagedDatum object to another object and verify both objects have the same value:

ManagedDatum strObj1(&ta);
strObj1 = strObj;
assert(strObj == strObj1);

Next, copy-construct this ManagedDatum object and verify that the copy has the same value as the original:

const ManagedDatum strObj2(strObj, &ta);
assert(strObj == strObj2);

Then, we create a ManagedDatum object that holds an opaque pointer to a bdlt::Date object and verify that the managed Date has the expected value:

ManagedDatum udtObj(Datum::createUdt(&udt, UDT_TYPE), &ta);
assert(udtObj->isUdt());
assert(&udt == udtObj->theUdt().data());
assert(UDT_TYPE == udtObj->theUdt().type());
Definition bdlt_date.h:294

Next, we assign a boolean value to this ManagedDatum object and verify that it has the new type and value:

udtObj.adopt(Datum::createBoolean(true));
assert(udtObj->isBoolean());
assert(true == udtObj->theBoolean());

Then, we create a ManagedDatum object having an array and verify that it has the same array value. Note that in practice we would use bdld_datumarraybuilder , but do not do so here for dependency reasons:

const Datum datumArray[2] = {
Datum::createInteger(12),
Datum::copyString("A long string", &ta)
};
DatumMutableArrayRef arr;
Datum::createUninitializedArray(&arr, 2, &ta);
for (int i = 0; i < 2; ++i) {
arr.data()[i] = datumArray[i];
}
*(arr.length()) = 2;
const ManagedDatum arrayObj(Datum::adoptArray(arr), &ta);
assert(arrayObj->isArray());
assert(DatumArrayRef(datumArray, 2) == arrayObj->theArray());

Next, we create a ManagedDatum object having a map and verify that it has the same map value. Note that in practice we would use bdld_datummapbuilder , but do not do so here to for dependency reasons.

const DatumMapEntry datumMap[2] = {
DatumMapEntry(StringRef("first", static_cast<int>(strlen("first"))),
Datum::createInteger(12)),
DatumMapEntry(StringRef("second", static_cast<int>(strlen("second"))),
Datum::copyString("A very long string", &ta))
};
DatumMutableMapRef mp;
Datum::createUninitializedMap(&mp, 2, &ta);
for (int i = 0; i < 2; ++i) {
mp.data()[i] = datumMap[i];
}
*(mp.size()) = 2;
const ManagedDatum mapObj(Datum::adoptMap(mp), &ta);
assert(mapObj->isMap());
assert(DatumMapRef(datumMap, 2, false, false) == mapObj->theMap());

Then, we create a Datum object and assign its ownership to a ManagedDatum object and verify that the ownership was transferred:

const Datum rcObj = Datum::copyString("This is a string", &ta);
ManagedDatum obj(Datum::createInteger(1), &ta);
obj.adopt(rcObj);
assert(obj.datum() == rcObj);

Next, we release the Datum object managed by obj and verify that it was released:

const Datum internalObj = obj.release();
assert(obj->isNull());
assert(internalObj == rcObj);

Finally, we destroy the released Datum object:

Datum::destroy(internalObj, obj.get_allocator());