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

Detailed Description

Provide utilities for pointer manipulation.

Outline

Usage

Purpose

Provide utilities for pointer manipulation.

Classes

Description

This component provides a utility struct, bslma::PointerUtil, that serves as a namespace for static functions that perform low-level pointer manipulations useful for implementing portable generic facilities. voidify returns a void * from a pointer to a potentially cv-qualified type, or from a function pointer on platforms that support the conversion. unqualify returns a pointer to the cv-unqualified version of the pointed-to type, or returns a function pointer unchanged.

Function Pointers and void

Conversion from a pointer-to-function to void * requires a reinterpret_cast and is conditionally-supported behavior in C++17; prior to C++17 it is undefined behavior. In practice, this conversion is well-defined on all platforms that BDE is known to support, and is formally a part of the POSIX Standard.

Usage

This section illustrates intended use of this component.

Example 1: Using voidify for Placement New

Suppose we are implementing a simplified optional-like container that holds a value of (template parameter) TYPE in a raw buffer. TYPE may be const-qualified (e.g., MyOptional<const int>).

First, we define the class template with an aligned buffer and a flag:

template <class TYPE>
class MyOptional {
// DATA
union {
char d_buf[sizeof(TYPE)];
};
bool d_hasValue;
public:
// CREATORS
MyOptional() : d_hasValue(false) {}
// MANIPULATORS
/// Construct a `TYPE` object in this object's buffer having its
/// default value, and return a reference to the newly created
/// object.
TYPE& emplace();
// ACCESSORS
bool hasValue() const { return d_hasValue; }
const TYPE& value() const
{
return *reinterpret_cast<const TYPE *>(d_buf);
}
};
AlignmentToType< BSLS_MAX_ALIGNMENT >::Type MaxAlignedType
Definition bsls_alignmentutil.h:307

Then we implement emplace. We declare a pointer of the correct type to the return value so that we can efficiently return a reference to the object we are about to create.

template <class TYPE>
TYPE& MyOptional<TYPE>::emplace()
{
BSLS_ASSERT(!d_hasValue);
TYPE *addr = reinterpret_cast<TYPE *>(d_buf);
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976

Now, we use voidify to provide the address at which to construct the new object. A placement-new expression requires a void * operand, but TYPE may be cv-qualified and static_cast alone cannot produce void * from a pointer to a cv-qualified type.

addr = ::new (bslma::PointerUtil::voidify(addr)) TYPE();
d_hasValue = true;
return *addr;
}
static BSLS_KEYWORD_CONSTEXPR void * voidify(TYPE *address) BSLS_KEYWORD_NOEXCEPT
Definition bslma_pointerutil.h:350

Finally, we can use MyOptional with a const-qualified type. Without voidify, the placement new inside emplace would not compile:

MyOptional<const int> opt;
const int& ref = opt.emplace();
assert(opt.hasValue());
assert(0 == ref);

Example 2: Using unqualify for Generic Forwarding

Suppose we are given a construction facility that constructs an object of (template parameter) TYPE at a specified address having its default value, and returns a pointer to the newly created object:

/// Construct an object of the specified (template parameter) `TYPE` at
/// the specified `address` having its default value, and return
/// `address`.
template <class TYPE>
TYPE *constructInPlace(TYPE *address);

When forwarding to such a facility from our own generic code, we can strip any cv-qualification with unqualify so that the downstream facility is always invoked with the unqualified type, avoiding a redundant template instantiation for each cv-variant of the same underlying type across the entire program. Casting away const is well-defined when the underlying storage was not originally declared const – as is typical for raw buffers managed by containers and allocators. Observe that the int * returned by constructInPlace implicitly converts to const int * or volatile int * when assigned back, correctly preserving the original cv-qualification:

union {
char d_buf[sizeof(int)];
} u = {};
int *ip = reinterpret_cast<int *>(u.d_buf);
const int *cp = reinterpret_cast<const int *>(u.d_buf);
volatile int *vp = reinterpret_cast<volatile int *>(u.d_buf);
ip = constructInPlace(bslma::PointerUtil::unqualify(ip));
assert(0 == *ip);
cp = constructInPlace(bslma::PointerUtil::unqualify(cp));
assert(0 == *cp);
vp = constructInPlace(bslma::PointerUtil::unqualify(vp));
assert(0 == *vp);
static BSLS_KEYWORD_CONSTEXPR TYPE * unqualify(TYPE *address) BSLS_KEYWORD_NOEXCEPT
Definition bslma_pointerutil.h:301