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

Macros

#define bslalg_ConstructorProxy   bslalg::ConstructorProxy
 This alias is defined for backward compatibility.
 

Detailed Description

Outline

Purpose

Provide a proxy for constructing and destroying objects.

Classes

See also
bslma_allocator

Description

This component provides a proxy class template, bslalg::ConstructorProxy, for creating a proxied object of parameter type OBJECT_TYPE using a uniform constructor syntax, regardless of whether OBJECT_TYPE is allocator-aware (AA) – i.e., uses an allocator to supply memory. This proxy is useful in generic programming situations where an object of a given type must be constructed, but it is not known in advance which allocator model the object supports, if any. In these situations, client code unconditionally passes an allocator as the last argument to the ConstructorProxy constructor; the constructor forwards the allocator to the proxied object if OBJECT_TYPE is AA and discards it otherwise.

The proxied object is owned by the ConstructorProxy object. Modifiable and non-modifiable access to the proxied object may be obtained using the overloaded object methods. When the proxy is destroyed, it automatically destroys its proxied object.

See the bslma package-level documentation for more information about using allocators.

Usage

Example 1: Conditionally pass an allocator to a template member ctor

In this example, we create a key-value class template consiting of a string key paired with a value of template-parameter type. Since the value type might be allocator aware (AA), we want to ensure that our key-value class template can pass an allocator to its value-type constructor.

First, we define a simple AA string class that will be our value type for testing:

#include <cstring>
// Basic allocator-aware string class.
class String {
// DATA
bsl::allocator<char> d_allocator;
std::size_t d_length;
char *d_data;
public:
// TYPES
typedef bsl::allocator<char> allocator_type;
// CREATORS
String(const char *str = "",
const allocator_type& a = allocator_type()); // IMPLICIT
String(const String& original,
const allocator_type& a = allocator_type());
~String();
// MANIPULATORS
String& operator=(const String& rhs);
// ACCESSORS
const char* c_str() const { return d_data; }
allocator_type get_allocator() const { return d_allocator; }
std::size_t size() const { return d_length; }
};
// FREE FUNCTIONS
bool operator==(const String& a, const String& b);
bool operator!=(const String& a, const String& b);
Definition bslma_bslallocator.h:580
bool operator!=(const FileCleanerConfiguration &lhs, const FileCleanerConfiguration &rhs)
bool operator==(const FileCleanerConfiguration &lhs, const FileCleanerConfiguration &rhs)
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.

Next, we define the constructors, destructor, and equality-comparison operators. For brevity, we've omited the implementation of the assignment operator, which is not used in this example:

String::String(const char *str, const allocator_type& a)
: d_allocator(a), d_length(std::strlen(str))
{
d_data = static_cast<char *>(
std::memcpy(d_data, str, d_length + 1);
}
String::String(const String& original, const allocator_type& a)
: d_allocator(a), d_length(original.d_length)
{
d_data = static_cast<char *>(
std::memcpy(d_data, original.c_str(), d_length);
d_data[d_length] = '\0';
}
String::~String()
{
bslma::AllocatorUtil::deallocateBytes(d_allocator, d_data, d_length+1);
}
bool operator==(const String& a, const String& b)
{
return (a.size() == b.size() &&
0 == std::memcmp(a.c_str(), b.c_str(), a.size()));
}
bool operator!=(const String& a, const String& b)
{
return ! (a == b);
}
Definition bdldfp_decimal.h:5188
static void deallocateBytes(const t_ALLOCATOR &allocator, typename AllocatorUtil_Traits< t_ALLOCATOR >::void_pointer p, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_allocatorutil.h:911
static AllocatorUtil_Traits< t_ALLOCATOR >::void_pointer allocateBytes(const t_ALLOCATOR &allocator, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_allocatorutil.h:871

Now we are ready to define our key-value template. The data portion of the template needs a member for the key and one for the value. Rather than defining the value member as simply a member variable of TYPE, we use bslalg::ConstructorProxy to ensure that we will be able to construct it in a uniform way even though we do not know whether or not it is allocator-aware:

/// Key-value pair with string key and arbitrary value type.
template <class TYPE>
class KeyValue {
// DATA
String d_key;
Definition bslalg_constructorproxy.h:368

Next, we declare the creators and manipulators typical of an AA attribute class:

public:
typedef bsl::allocator<> allocator_type;
// CREATORS
KeyValue(const String& k,
const TYPE& v,
const allocator_type& a = allocator_type());
KeyValue(const KeyValue& original,
const allocator_type& a = allocator_type());
~KeyValue();
// MANIPULATORS
KeyValue& operator=(const KeyValue& rhs);

Next, we declare the accessessors and, for convenience in this example, define them inline. Note that the value accessor extracts the proxied object from the d_valueProxy member:

// ACCESSESSORS
allocator_type get_allocator() const { return d_key.get_allocator(); }
const String& key() const { return d_key; }
const TYPE& value() const { return d_valueProxy.object(); }
};
OBJECT_TYPE & object() BSLS_KEYWORD_NOEXCEPT
Return a reference to the modifiable object held by this proxy.
Definition bslalg_constructorproxy.h:1187

Next, we define the value constructor, which passes its allocator argument to both data members' constructors. Note that the d_valueProxy, constructor always expects an allocator argument, even if TYPE is not AA:

template <class TYPE>
KeyValue<TYPE>::KeyValue(const String& k,
const TYPE& v,
const allocator_type& a)
: d_key(k, a), d_valueProxy(v, a)
{
}

Next, we define the copy constructor and assignment operator. Since bslalg::ConstructorProxy is not copyable, we must manually extract the proxied object in the assignment operator. This extraction is not needed in the copy constructor because the single-value proxy constructor automatically "unwraps" its argument when presented with an instantiation of bslalg::ConstructorProxy:

template <class TYPE>
KeyValue<TYPE>::KeyValue(const KeyValue& original,
const allocator_type& a)
: d_key(original.d_key, a)
, d_valueProxy(original.d_valueProxy, a) // Automatically unwrapped
{
}
template <class TYPE>
KeyValue<TYPE>& KeyValue<TYPE>::operator=(const KeyValue& rhs)
{
d_key = rhs.d_key;
d_valueProxy.object() = rhs.d_valueProxy.object();
return *this;
}

Last, we define the destructor, which does nothing explicit (and could therefore have been defaulted), because both String and ConstructorProxy clean up after themselves:

template <class TYPE>
KeyValue<TYPE>::~KeyValue()
{
}

Now we can illustrate the use of our key-value pair by defining a string-int pair and constructing it with a test allocator. Note that the allocator was passed to the (String) key, as we would expect:

int main()
{
KeyValue<int> kv1("hello", 2023, &ta);
assert("hello" == kv1.key());
assert(2023 == kv1.value());
assert(&ta == kv1.get_allocator());
assert(&ta == kv1.key().get_allocator());
Definition bslma_testallocator.h:384

Next, we define a string-string pair and show that the allocator was passed to both the key and value parts of the pair:

KeyValue<String> kv2("March", "Madness", &ta);
assert("March" == kv2.key());
assert("Madness" == kv2.value());
assert(&ta == kv2.get_allocator());
assert(&ta == kv2.key().get_allocator());
assert(&ta == kv2.value().get_allocator());

Finally, we declare a bslalg::ConstructorProxy of KeyValue and show how we can pass more than one argument (up to 14) – in addition to the allocator – to the proxied type's constructor:

typedef KeyValue<int> UnitVal;
bslalg::ConstructorProxy<UnitVal> uvProxy("km", 14, &ta);
UnitVal& uv = uvProxy.object();
assert("km" == uv.key());
assert(14 == uv.value());
assert(&ta == uv.get_allocator());
}

Macro Definition Documentation

◆ bslalg_ConstructorProxy

#define bslalg_ConstructorProxy   bslalg::ConstructorProxy