Provide a smart-pointer-like manager for a Datum
object.
More...
Namespaces |
namespace | bdld |
Detailed Description
- Outline
-
-
- Purpose:
- Provide a smart-pointer-like manager for a
Datum
object.
-
- Classes:
-
- See also:
- Component bdld_datum
-
- Description:
- This component implements a type,
bdld::ManagedDatum
, that provides two important services for Datum
objects:
-
ManagedDatum
provides value-semantic-like operations for Datum
.
-
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 bsldoc_glossary
|Value-Semantic Operations):
-
Equality and Non-Equality Comparisons
-
Copy Construction
-
Copy Assignment
-
Default Construction
-
ostream
Printing
- 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 'Datumclone, 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());
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: bdlt::Date udt;
ManagedDatum udtObj(Datum::createUdt(&udt, UDT_TYPE), &ta);
assert(udtObj->isUdt());
assert(&udt == udtObj->theUdt().data());
assert(UDT_TYPE == udtObj->theUdt().type());
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().mechanism());