BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdld_manageddatum

Detailed Description

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

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).

Additionally, move operations are supported (i.e. move constructor and move assignment). Depending on the match of the source and target allocators, ManagedDatum performs either shallow (the allocators are the same) or deep (the allocators are different) copying.

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:402

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());