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

Detailed Description

Provide an STL-compliant vector class.

Outline

Purpose

Provide an STL-compliant vector class.

Classes

Canonical Header

bsl_vector.h

See also
bslstl_deque

Description

This component defines a single class template, bsl::vector, implementing the standard sequential container, std::vector, holding a dynamic array of values of a template parameter type.

An instantiation of vector is an allocator-aware, value-semantic type whose salient attributes are its size (number of values) and the sequence of values the vector contains. If vector is instantiated with a value type that is not value-semantic, then the vector will not retain all of its value-semantic qualities. In particular, if a value type cannot be tested for equality, then a vector containing objects of that type cannot be tested for equality. It is even possible to instantiate vector with a value type that does not have a copy-constructor, in which case the vector will not be copyable.

A vector meets the requirements of a sequential container with random access iterators in the C++ standard [vector]. The vector implemented here adheres to the C++11 standard when compiled with a C++11 compiler, and makes the best approximation when compiled with a C++03 compiler. In particular, for C++03 we emulate move semantics, but limit forwarding (in emplace) to const lvalues, and make no effort to emulate noexcept or initializer lists.

Requirements on VALUE_TYPE

A vector is a fully Value-Semantic Type (see bsldoc_glossary ) only if the supplied VALUE_TYPE template parameter is fully value-semantic. It is possible to instantiate a vector with a VALUE_TYPE parameter that does not have a full set of value-semantic operations, but then some methods of the container may not be instantiable. The following terminology, adopted from the C++11 standard, is used in the function documentation of vector to describe a function's requirements for the VALUE_TYPE template parameter. These terms are also defined in section [17.6.3.1] of the C++11 standard. Note that, in the context of a vector instantiation, the requirements apply specifically to the vector's entry type, value_type, which is an alias for VALUE_TYPE.

Glossary

Legend
------
'X' - denotes an allocator-aware container type (e.g., 'vector')
'T' - 'value_type' associated with 'X'
'A' - type of the allocator used by 'X'
'm' - lvalue of type 'A' (allocator)
'p' - address ('T *') of uninitialized storage for a 'T' within an 'X'
'rv' - rvalue of type (non-'const') 'T'
'v' - rvalue or lvalue of type (possibly 'const') 'T'
'args' - 0 or more arguments

The following terms are used to more precisely specify the requirements on template parameter types in function-level documentation.

default-insertable: T has a default constructor. More precisely, T is default-insertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p)

move-insertable: T provides a constructor that takes an rvalue of type (non-const) T. More precisely, T is move-insertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p, rv)

copy-insertable: T provides a constructor that takes an lvalue or rvalue of type (possibly const) T. More precisely, T is copy-insertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p, v)

move-assignable: T provides an assignment operator that takes an rvalue of type (non-const) T.

copy-assignable: T provides an assignment operator that takes an lvalue or rvalue of type (possibly const) T.

emplace-constructible: T is emplace-constructible into X from args means that the following expression is well-formed: allocator_traits<A>::construct(m, p, args)

erasable: T provides a destructor. More precisely, T is erasable from X means that the following expression is well-formed: allocator_traits<A>::destroy(m, p)

equality-comparable: The type provides an equality-comparison operator that defines an equivalence relationship and is both reflexive and transitive.

Memory Allocation

The type supplied as a vector's ALLOCATOR template parameter determines how that vector will allocate memory. The vector template supports allocators meeting the requirements of the C++03 standard; in addition, it supports scoped-allocators derived from the bslma::Allocator memory allocation protocol. Clients intending to use bslma-style allocators should use the template's default ALLOCATOR type: The default type for the ALLOCATOR template parameter, bsl::allocator, provides a C++11 standard-compatible adapter for a bslma::Allocator object.

bslma-Style Allocators

If the (template parameter) type ALLOCATOR of a vector instantiation' is bsl::allocator, then objects of that vector type will conform to the standard behavior of a bslma-allocator-enabled type. Such a vector accepts an optional bslma::Allocator argument at construction. If the address of a bslma::Allocator object is explicitly supplied at construction, it is used to supply memory for the vector throughout its lifetime; otherwise, the vector will use the default allocator installed at the time of the vector's construction (see bslma_default ). In addition to directly allocating memory from the indicated bslma::Allocator, a vector supplies that allocator's address to the constructors of contained objects of the (template parameter) type VALUE_TYPE, if it defines the bslma::UsesBslmaAllocator trait.

Operations

This section describes the run-time complexity of operations on instances of vector:

Legend
------
'V' - (template parameter) 'VALUE_TYPE' of the vector
'a', 'b' - two distinct objects of type 'vector<V>'
'rv' - modifiable rvalue of type 'vector<V>'
'n', 'm' - number of elements in 'a' and 'b', respectively
'k' - non-negative integer
'al' - an STL-style memory allocator
'i1', 'i2' - two iterators defining a sequence of 'V' objects
'rg' - range of objects convertible to 'V'
'il' - object of type 'std::initializer_list<V>'
'lil' - length of 'il'
'vt' - object of type 'VALUE_TYPE'
'rvt' - modifiable rvalue of type 'VALUE_TYPE'
'p1', 'p2' - two 'const' iterators belonging to 'a'
distance(i1,i2) - the number of elements in the range [i1, i2)
|-----------------------------------------+-------------------------------|
| Operation | Complexity |
|=========================================+===============================|
| vector<V> a (default construction) | O[1] |
| vector<V> a(al) | |
|-----------------------------------------+-------------------------------|
| vector<V> a(b) (copy construction) | O[n] |
| vector<V> a(b, al) | |
|-----------------------------------------+-------------------------------|
| vector<V> a(rv) (move construction) | O[1] if 'a' and 'rv' use the |
| vector<V> a(rv, al) | same allocator; O[n] otherwise|
|-----------------------------------------+-------------------------------|
| vector<V> a(k) | O[k] |
| vector<V> a(k, al) | |
| vector<V> a(k, vt) | |
| vector<V> a(k, vt, al) | |
|-----------------------------------------+-------------------------------|
| vector<V> a(i1, i2) | O[distance(i1, i2)] |
| vector<V> a(i1, i2, al) | |
|-----------------------------------------+-------------------------------|
| vector<V> a(from_range, rg) | O[ranges::distance(rg)] |
| vector<V> a(from_range, rg, al) | |
|-----------------------------------------+-------------------------------|
| vector<V> a(il) | O[lil] |
| vector<V> a(il, al) | |
|-----------------------------------------+-------------------------------|
| a.~vector<V>() (destruction) | O[n] |
|-----------------------------------------+-------------------------------|
| a.assign(k, vt) | O[k] |
| a.assign(k, rvt) | |
|-----------------------------------------+-------------------------------|
| a.assign(i1, i2) | O[distance(i1, i2)] |
|-----------------------------------------+-------------------------------|
| a.assign_range(rg) | O[ranges::distance(rg)] |
|-----------------------------------------+-------------------------------|
| a.assign(il) | O[lil] |
|-----------------------------------------+-------------------------------|
| get_allocator() | O[1] |
|-----------------------------------------+-------------------------------|
| a.begin(), a.end(), | O[1] |
| a.cbegin(), a.cend(), | |
| a.rbegin(), a.rend(), | |
| a.crbegin(), a.crend() | |
|-----------------------------------------+-------------------------------|
| a.size() | O[1] |
|-----------------------------------------+-------------------------------|
| a.max_size() | O[1] |
|-----------------------------------------+-------------------------------|
| a.resize(k) | O[k] |
| a.resize(k, vt) | |
|-----------------------------------------+-------------------------------|
| a.empty() | O[1] |
|-----------------------------------------+-------------------------------|
| a.reserve(k) | O[k] |
|-----------------------------------------+-------------------------------|
| a.shrink_to_fit() | O[n] |
|-----------------------------------------+-------------------------------|
| a[k] | O[1] |
|-----------------------------------------+-------------------------------|
| a.at(k) | O[1] |
|-----------------------------------------+-------------------------------|
| a.front() | O[1] |
|-----------------------------------------+-------------------------------|
| a.back() | O[1] |
|-----------------------------------------+-------------------------------|
| a.push_back(vt) | O[1] |
| a.push_back(rvt) | |
|-----------------------------------------+-------------------------------|
| a.pop_back() | O[1] |
|-----------------------------------------+-------------------------------|
| a.emplace_back(args) | O[1] |
|-----------------------------------------+-------------------------------|
| a.append_range(rg) | O[ranges::distance(rg)] |
|-----------------------------------------+-------------------------------|
| a.emplace(p1, args) | O[1 + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.insert(p1, vt) | O[1 + distance(p1, a.end())] |
| a.insert(p1, rvt) | |
|-----------------------------------------+-------------------------------|
| a.insert(p1, k, vt) | O[k + distance(p1, a.end())] |
| a.insert(p1, k, rvt) | |
|-----------------------------------------+-------------------------------|
| a.insert(p1, i1, i2) | O[distance(i1, i2) |
| | + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.insert_range(p1, rg) | O[ranges::distance(rg) + |
| | ranges::distance(p1, |
| | a.end())] |
|-----------------------------------------+-------------------------------|
| a.insert(p1, il) | O[lil |
| | + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.erase(p1) | O[1 + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.erase(p1, p2) | O[distance(p1, p2) |
| | + distance(p1, a.end())] |
|-----------------------------------------+-------------------------------|
| a.swap(b), swap(a, b) | O[1] if 'a' and 'b' use the |
| | same allocator; O[n + m] |
| | otherwise |
|-----------------------------------------+-------------------------------|
| a.clear() | O[n] |
|-----------------------------------------+-------------------------------|
| a = b; (copy assignment) | O[n] |
|-----------------------------------------+-------------------------------|
| a = rv; (move assignment) | O[1] if 'a' and 'rv' use the |
| | same allocator; O[n] otherwise|
|-----------------------------------------+-------------------------------|
| a = il; | O[lil] |
|-----------------------------------------+-------------------------------|
| a == b, a != b | O[n] |
|-----------------------------------------+-------------------------------|
| a < b, a <= b, a > b, a >= b | O[n] |
|-----------------------------------------+-------------------------------|

Comparing a vector of floating point values

The comparison operator performs a bit-wise comparison for floating point types (float and double), which produces results for NaN, +0, and -0 values that do not meet the guarantees provided by the standard. The bslmf::IsBitwiseEqualityComparable trait for double and float types returns true which is incorrect because a comparison with a NaN value is always false, and -0 and +0 are equal.

v.push_back(bsl::numeric_limits<double>::quiet_NaN());
ASSERT(v == v); // This assertion will *NOT* fail!
Definition bslstl_vector.h:1120
void push_back(const VALUE_TYPE &value)
Definition bslstl_vector.h:4343

Addressing this issue, i.e., updating bslmf::IsBitwiseEqualityComparable to return false for floating point types, could potentially destabilize production software so the change (for the moment) has not been made.

Usage

In this section we show intended use of this component.

Example 1: Creating a Matrix Type

Suppose we want to define a value-semantic type representing a dynamically resizable two-dimensional matrix.

First, we define the public interface for the MyMatrix class template:

/// This value-semantic type characterizes a two-dimensional matrix of
/// objects of the (template parameter) `TYPE`. The numbers of columns
/// and rows of the matrix can be specified at construction and, at any
/// time, via the `reset`, `insertRow`, and `insertColumn` methods. The
/// value of each element in the matrix can be set and accessed using
/// the `theValue`, and `theModifiableValue` methods respectively.
template <class TYPE>
class MyMatrix {
public:
// PUBLIC TYPES

Here, we create a type alias, RowType, for an instantiation of bsl::vector to represent a row of TYPE objects in the matrix. We create another type alias, MatrixType, for an instantiation of bsl::vector to represent the entire matrix of TYPE objects as a list of rows:

/// This is an alias representing a row of values of the (template
/// parameter) `TYPE`.
typedef bsl::vector<TYPE> RowType;
/// This is an alias representing a two-dimensional matrix of values
/// of the (template parameter) `TYPE`.
typedef bsl::vector<RowType> MatrixType;
private:
// DATA
MatrixType d_matrix; // matrix of values
int d_numColumns; // number of columns
// FRIENDS
template <class T>
friend bool operator==(const MyMatrix<T>&, const MyMatrix<T>&);
public:
// PUBLIC TYPES
typedef typename MatrixType::const_iterator ConstRowIterator;
// CREATORS
// Create a `MyMatrix` object having the specified `numRows` and
// the specified `numColumns`. All elements of the (template
// parameter) `TYPE` in the matrix will have the
// default-constructed value. Optionally specify a
// `basicAllocator` used to supply memory. If `basicAllocator` is
// 0, the currently installed default allocator is used. The
// behavior is undefined unless `0 <= numRows` and
// `0 <= numColumns`
MyMatrix(int numRows,
int numColumns,
bslma::Allocator *basicAllocator = 0);
// Create a `MyMatrix` object having the same value as the
// specified `original` object. Optionally specify a
// `basicAllocator` used to supply memory. If `basicAllocator` is
// 0, the currently installed default allocator is used.
MyMatrix(const MyMatrix& original,
bslma::Allocator *basicAllocator = 0);
/// Destroy this object.
//! ~MyMatrix = default;
// MANIPULATORS
/// Assign to this object the value of the specified `rhs` object,
/// and return a reference providing modifiable access to this
/// object.
MyMatrix& operator=(const MyMatrix& rhs);
/// Remove all rows and columns from this object.
void clear();
/// Insert, into this matrix, an column at the specified
/// `columnIndex`. All elements of the (template parameter) `TYPE`
/// in the column will have the default-constructed value. The
/// behavior is undefined unless `0 <= columnIndex <= numColumns()`.
void insertColumn(int columnIndex);
/// Insert, into this matrix, a row at the specified `rowIndex`.
/// All elements of the (template parameter) `TYPE` in the row will
/// have the default-constructed value. The behavior is undefined
/// unless `0 <= rowIndex <= numRows()`.
void insertRow(int rowIndex);
/// Return a reference providing modifiable access to the element at
/// the specified `rowIndex` and the specified `columnIndex` in this
/// matrix. The behavior is undefined unless
/// `0 <= rowIndex < numRows()` and
/// `0 <= columnIndex < numColumns()`.
TYPE& theModifiableValue(int rowIndex, int columnIndex);
// ACCESSORS
/// Return the number of rows in this matrix.
int numRows() const;
/// Return the number of columns in this matrix.
int numColumns() const;
/// Return an iterator providing non-modifiable access to the
/// `RowType` objects representing the first row in this matrix.
ConstRowIterator beginRow() const;
/// Return an iterator providing non-modifiable access to the
/// `RowType` objects representing the past-the-end row in this
/// matrix.
ConstRowIterator endRow() const;
/// Return a reference providing non-modifiable access to the
/// element at the specified `rowIndex` and the specified
/// `columnIndex` in this matrix. The behavior is undefined unless
/// `0 <= rowIndex < numRows()` and
/// `0 <= columnIndex < numColumns()`.
const TYPE& theValue(int rowIndex, int columnIndex) const;
};
Definition bslma_allocator.h:545

Then we declare the free operator for MyMatrix:

// FREE OPERATORS
/// Return `true` if the specified `lhs` and `rhs` objects have the same
/// value, and `false` otherwise. Two `MyMatrix` objects have the same
/// value if they have the same number of rows and columns and every
/// element in both matrices compare equal.
template <class TYPE>
MyMatrix<TYPE> operator==(const MyMatrix<TYPE>& lhs,
const MyMatrix<TYPE>& rhs);
/// Return `true` if the specified `lhs` and `rhs` objects do not have
/// the same value, and `false` otherwise. Two `MyMatrix` objects do
/// not have the same value if they do not have the same number of rows
/// and columns or every element in both matrices do not compare equal.
template <class TYPE>
MyMatrix<TYPE> operator!=(const MyMatrix<TYPE>& lhs,
const MyMatrix<TYPE>& rhs);
/// Return a `MyMatrix` objects that is the product of the specified
/// `lhs` and `rhs`. The behavior is undefined unless
/// `lhs.numColumns() == rhs.numRows()`.
template <class TYPE>
MyMatrix<TYPE> operator*(const MyMatrix<TYPE>& lhs,
const MyMatrix<TYPE>& rhs);

Now, we define the methods of MyMatrix:

// CREATORS
template <class TYPE>
MyMatrix<TYPE>::MyMatrix(int numRows,
int numColumns,
bslma::Allocator *basicAllocator)
: d_matrix(numRows, basicAllocator)
, d_numColumns(numColumns)
{
BSLS_ASSERT(0 <= numRows);
BSLS_ASSERT(0 <= numColumns);
for (typename MatrixType::iterator itr = d_matrix.begin();
itr != d_matrix.end();
++itr) {
itr->resize(d_numColumns);
}
}
template <class TYPE>
MyMatrix<TYPE>::MyMatrix(const MyMatrix& original,
bslma::Allocator *basicAllocator)
: d_matrix(original.d_matrix, basicAllocator)
, d_numColumns(original.d_numColumns)
{
}
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976

Notice that we pass the contained bsl::vector (d_matrix) the allocator specified at construction to supply memory. If the (template parameter) TYPE of the elements has the bslalg_TypeTraitUsesBslmaAllocator trait, this allocator will be passed by the vector to the elements as well.

// MANIPULATORS
template <class TYPE>
MyMatrix<TYPE>& MyMatrix<TYPE>::operator=(const MyMatrix& rhs)
{
d_matrix = rhs.d_matrix;
d_numColumns = rhs.d_numColumns;
}
template <class TYPE>
void MyMatrix<TYPE>::clear()
{
d_matrix.clear();
d_numColumns = 0;
}
template <class TYPE>
void MyMatrix<TYPE>::insertColumn(int colIndex) {
for (typename MatrixType::iterator itr = d_matrix.begin();
itr != d_matrix.end();
++itr) {
itr->insert(itr->begin() + colIndex, TYPE());
}
++d_numColumns;
}
template <class TYPE>
void MyMatrix<TYPE>::insertRow(int rowIndex)
{
typename MatrixType::iterator itr =
d_matrix.insert(d_matrix.begin() + rowIndex, RowType());
itr->resize(d_numColumns);
}
template <class TYPE>
TYPE& MyMatrix<TYPE>::theModifiableValue(int rowIndex, int columnIndex)
{
BSLS_ASSERT(0 <= rowIndex);
BSLS_ASSERT(rowIndex < d_matrix.size());
BSLS_ASSERT(0 <= columnIndex);
BSLS_ASSERT(columnIndex < d_numColumns);
return d_matrix[rowIndex][columnIndex];
}
// ACCESSORS
template <class TYPE>
int MyMatrix<TYPE>::numRows() const
{
return d_matrix.size();
}
template <class TYPE>
int MyMatrix<TYPE>::numColumns() const
{
return d_numColumns;
}
template <class TYPE>
typename MyMatrix<TYPE>::ConstRowIterator MyMatrix<TYPE>::beginRow() const
{
return d_matrix.begin();
}
template <class TYPE>
typename MyMatrix<TYPE>::ConstRowIterator MyMatrix<TYPE>::endRow() const
{
return d_matrix.end();
}
template <class TYPE>
const TYPE& MyMatrix<TYPE>::theValue(int rowIndex, int columnIndex) const
{
BSLS_ASSERT(0 <= rowIndex);
BSLS_ASSERT(rowIndex < d_matrix.size());
BSLS_ASSERT(0 <= columnIndex);
BSLS_ASSERT(columnIndex < d_numColumns);
return d_matrix[rowIndex][columnIndex];
}

Finally, we defines the free operators for MyMatrix:

// FREE OPERATORS
template <class TYPE>
MyMatrix<TYPE> operator==(const MyMatrix<TYPE>& lhs,
const MyMatrix<TYPE>& rhs)
{
return lhs.d_numColumns == rhs.d_numColumns &&
lhs.d_matrix == rhs.d_matrix;
}
template <class TYPE>
MyMatrix<TYPE> operator!=(const MyMatrix<TYPE>& lhs,
const MyMatrix<TYPE>& rhs)
{
return !(lhs == rhs);
}

Macro Definition Documentation

◆ BSLSTL_VECTOR_REQUIRES_CONTAINER_COMPATIBLE_RANGE

#define BSLSTL_VECTOR_REQUIRES_CONTAINER_COMPATIBLE_RANGE (   R,
 
)