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

Detailed Description

Provide a simple struct with two members that may use allocators.

Outline

Purpose

Provide a simple struct with two members that may use allocators.

Classes

Canonical Header

bsl_utility.h

Description

bsl::pair is an allocator-aware version of std::pair. The bsl::pair class template is instantiated on two types, T1 and T2, and provides two public data members, first and second of types T1 and T2, respectively. Each data member might or might not allocate memory using bslma::Allocator. Its interface is identical to std::pair except that it has constructors that take optional allocator arguments to correctly construct the member variables. For example, a bsl::pair<bsl::string, int> has member first of type bsl::string and second of type int. A client can pass a bslma::Allocator pointer to the pair constructor and the constructor will pass it through to the first member. Similarly, the copy constructor takes an optional bslma::Allocator pointer and copy-constructs the first member using that allocator.

bsl::pair is unusual in that its data members, first and second, are public. Once constructed, a client program accesses these members directly. This part of the interface is identical to std::pair, for which bsl::pair is intended to be a drop-in replacement.

bsl::pair has four constructors: a default constructor that default-constructs the two data members, a copy constructor that copy-constructs each data member, a constructor taking two arguments of type T1 and T2, which are used to copy-construct first and second respectively, and a conversion constructor template for converting from a bsl::pair of different types, PARAM_1 and PARAM_2, provided PARAM_1 is convertible to T1 and PARAM_2 is convertible to T2. Each constructor also has an optional bslma::Allocator pointer argument. If neither T1 nor T2 use bslma::Allocator, this argument is ignored. Otherwise, either first or second, or both, depending on whether each type uses bslma::Allocator, will be passed the bslma::Allocator* argument during construction. Whether or not a type uses bslma::Allocator is determined by querying the bslma::UsesBslmaAllocator trait for that type. This component also defines a full set of equality and relational operators that can be instantiated if T1 and T2 both provide those operators.

A bsl::pair declares a set of associated type traits that are computed from the type traits of T1 and T2. For each supported type trait, a given specialization of bsl::pair has that trait if and only if both T1 and T2 have that trait. Supported traits are:

Definition bslmf_istriviallycopyable.h:324
Definition bslmf_istriviallydefaultconstructible.h:296
Definition bslmf_isbitwiseequalitycomparable.h:500
Definition bslmf_isbitwisemoveable.h:718

In addition, a bsl::pair specialization has the bslma::UsesBslmaAllocator trait if either T1 or T2 have that trait, or both.

Enhancements Enabled by Modern Language Standards

Language standards after the first (C++98) and its corrigendum (C++03) have added code C++ language features, type traits as well as requirements that affect the exact interface pair provides. This section describes such enhancements as they become available.

Conditional Default Constructor (C++11)

C++11 has introduced type traits, many of which needs compiler backing to be (automatically implementable) and also introduced "defaulted" (special member) functions that generate code without making mistakes. Before C++11 it was not possible to determine if a type had a default constructor in a non-intrusive manner. C++11 makes it possible using <type_traits> to determine that, and = default makes it possible to create special member functions that exists only when they can be implemented properly.

Hence, when using compilers with a reasonably complete implementation of C++11 we implement the default constructor of pair only if both types inside the pair type have a default constructor. Note that it means that when using C++11 a bsl::pair that stores a reference type (such as int&), or any other type that cannot be default constructed using the syntax T v{};, will cause pair to neither declare nor define a default constructor. So from C++11 onwards a type of bsl::pair<T1, T2> will have a default constructor only if both types T1 and T2 are default constructible. Otherwise, pair will have a default constructor that gives a compile-error (only) if called.

Usage

A bsl::pair is a very simple object when used without allocators. Our usage example concentrates on the use of allocators with bsl::pair. First, we create a utility function that copies a null-terminated string into memory allocated from a supplied allocator:

char *myStrDup(const char *s, bslma::Allocator *basicAllocator)
// Copy the specified null-terminated string 's' into memory allocated
// from the specified 'basicAllocator'
{
char *result = (char*) basicAllocator->allocate(std::strlen(s) + 1);
return std::strcpy(result, s);
}
Definition bslma_allocator.h:545
virtual void * allocate(size_type size)=0

We create a simple string class that holds strings allocated from a supplied allocator. It uses myStrDup (above) in its implementation:

class my_String {
// Simple string class that uses a 'bslma::Allocator' allocator.
bslma::Allocator *d_allocator_p;
char *d_data;
public:
explicit my_String(bslma::Allocator *basicAllocator = 0);
// Construct an empty string using the optionally-specified
// allocator 'basicAllocator'.
my_String(const char* s, bslma::Allocator *alloc = 0); // IMPLICIT
// Construct a string with contents specified in 's' using the
// optionally-specified allocator 'basicAllocator'.
my_String(const my_String& rhs, bslma::Allocator *alloc = 0);
// Construct a copy of the specified 'rhs' string using the
// optionally-specified allocator 'basicAllocator'.
~my_String();
// Destroy this string.
my_String& operator=(const my_String& rhs);
// Copy specified 'rhs' string value to this string.
const char* c_str() const;
// Return the null-terminated character array for this string.
bslma::Allocator *allocator() const;
// Return the allocator used to construct this string or, if no
// allocator was specified at construction, the default allocator
// at the time of construction.
};
bool operator==(const my_String& str1, const my_String& str2)
{
return 0 == std::strcmp(str1.c_str(), str2.c_str());
}
bool operator==(const my_String& str, const char *p)
{
return 0 == std::strcmp(p, str.c_str());
}
bool operator==(const char *p, const my_String& str)
{
return str == p;
}
bool operator!=(const my_String& str1, const my_String& str2)
{
return ! (str1 == str2);
}
bool operator!=(const my_String& str, const char *p)
{
return ! (str == p);
}
bool operator!=(const char *p, const my_String& str)
{
return ! (str == p);
}
bool operator<(const my_String& str1, const my_String& str2)
{
return std::strcmp(str1.c_str(), str2.c_str()) < 0;
}
my_String::my_String(bslma::Allocator *basicAllocator)
: d_allocator_p(bslma::Default::allocator(basicAllocator)), d_data(0)
{
d_data = myStrDup("", d_allocator_p);
}
my_String::my_String(const char *s, bslma::Allocator *basicAllocator)
: d_allocator_p(bslma::Default::allocator(basicAllocator)), d_data(0)
{
d_data = myStrDup(s, d_allocator_p);
}
my_String::my_String(const my_String& rhs,
bslma::Allocator *basicAllocator)
: d_allocator_p(bslma::Default::allocator(basicAllocator)), d_data(0)
{
d_data = myStrDup(rhs.d_data, d_allocator_p);
}
my_String::~my_String()
{
d_allocator_p->deallocate(d_data);
}
my_String& my_String::operator=(const my_String& rhs)
{
if (this != &rhs) {
d_allocator_p->deallocate(d_data);
d_data = myStrDup(rhs.d_data, d_allocator_p);
}
return *this;
}
const char *my_String::c_str() const
{
return d_data;
}
bslma::Allocator *my_String::allocator() const
{
return d_allocator_p;
}
#define BSLMF_NESTED_TRAIT_DECLARATION(t_TYPE, t_TRAIT)
Definition bslmf_nestedtraitdeclaration.h:231
bool operator!=(const FileCleanerConfiguration &lhs, const FileCleanerConfiguration &rhs)
bool operator==(const FileCleanerConfiguration &lhs, const FileCleanerConfiguration &rhs)
bool operator<(const MetricId &lhs, const MetricId &rhs)
ALLOCATOR const STRING_VIEW_LIKE_TYPE & rhs
Definition bslstl_string.h:3918
Definition baljsn_encoder_testtypes.h:76
Definition bslma_usesbslmaallocator.h:344

Our main program creates a mapping from strings to integers. Each node of the mapping consists of a bsl::pair<my_String, int>. The program allocates memory from a test allocator in order to ensure that there are no leaks:

int main()
{
Node *mapping[3];
Definition bslstl_pair.h:1280
Definition bslma_testallocator.h:402

When constructing a Node, an allocator is supplied in addition to parameters for the first and second data members.

{
mapping[0] = new(basicAllocator) Node("One", 1, &basicAllocator);
mapping[1] = new(basicAllocator) Node("Three", 3, &basicAllocator);
mapping[2] = new(basicAllocator) Node("Two", 2, &basicAllocator);
// Temporaries get destroyed here, even on broken compilers.
}
assert("One" == mapping[0]->first);
assert(1 == mapping[0]->second);
assert("Three" == mapping[1]->first);
assert(3 == mapping[1]->second);
assert("Two" == mapping[2]->first);
assert(2 == mapping[2]->second);
assert(6 == alloc.numBlocksInUse());
bsls::Types::Int64 numBlocksInUse() const
Definition bslma_testallocator.h:1370

Clean up at end.

alloc.deleteObjectRaw(mapping[0]);
alloc.deleteObjectRaw(mapping[1]);
alloc.deleteObjectRaw(mapping[2]);
assert(0 == alloc.numBlocksInUse());
return 0;
}
void deleteObjectRaw(const TYPE *object)
Definition bslma_allocator.h:804

Macro Definition Documentation

◆ BSLSTL_PAIR_DO_NOT_SFINAE_TEST_IS_SWAPPABLE

#define BSLSTL_PAIR_DO_NOT_SFINAE_TEST_IS_SWAPPABLE   1

The 'bsl::is_swappable' trait requires C++11 features, notably decltype, so cannot be back-ported to C++03. In a separate issue, early versions of MSVC, up to and including MSVC 2017 are unable to perform the required template argument deductions to enable the use of 'bsl::is_swappable' within the SFINAE test for 'swap()', and later version of MSVC retain this issue unless C++17 or later is enabled. In all cases we fall back on the previous, pre-C++17 implementation which simply assumes swappability and fails to compile when instantiated with a non-swappable type.