[container.requirements.general] (original) (raw)

22 Containers library [containers]

22.2.1 General container requirements [container.requirements.general]

Containers are objects that store other objects.

They control allocation and deallocation of these objects through constructors, destructors, insert and erase operations.

All of the complexity requirements in this Clause are stated solely in terms of the number of operations on the contained objects.

[ Example

:

The copy constructor of typevector<vector<int>>has linear complexity, even though the complexity of copying each containedvector<int>is itself linear.

end example

]

These functions are called only for the container's element type, not for internal types used by the container.

[ Note

:

This means, for example, that a node-based container might need to construct nodes containing aligned buffers and call construct to place the element into the buffer.

end note

]

In Tables 73,74, and75 X denotes a container class containing objects of type T,a and b denote values of type X,i and j denote values of type (possibly const) X​::​iterator,u denotes an identifier,r denotes a non-const value of type X, andrv denotes a non-const rvalue of type X.

Table 73: Container requirements [tab:container.req]

Expression Return type Operational Assertion/note Complexity
semantics pre-/post-condition
X​::​value_­type T Preconditions: T is Cpp17Erasable from X (see [container.requirements.general], below) compile time
X​::​reference T& compile time
X​::​const_­reference const T& compile time
X​::​iterator iterator type whose value type is T any iterator category that meets the forward iterator requirements. convertible to X​::​const_­iterator. compile time
X​::​const_­iterator constant iterator type whose value type is T any iterator category that meets the forward iterator requirements. compile time
X​::​difference_­type signed integer type is identical to the difference type of X​::​iterator and X​::​const_­iterator compile time
X​::​size_­type unsigned integer type size_­type can represent any non-negative value of difference_­type compile time
X u; Postconditions: u.empty() constant
X() Postconditions: X().empty() constant
X(a) Preconditions: T is Cpp17CopyInsertable into X (see below). Postconditions: a == X(a). linear
X u(a); X u = a; Preconditions: T is Cpp17CopyInsertable into X (see below). Postconditions: u == a linear
X u(rv); X u = rv; Postconditions: u is equal to the value that rv had before this construction (Note B)
a = rv X& All existing elements of a are either move assigned to or destroyed Postconditions: a is equal to the value that rv had before this assignment linear
a.~X() void Effects: destroys every element of a; any memory obtained is deallocated. linear
a.begin() iterator; const_­iterator for constant a constant
a.end() iterator; const_­iterator for constant a constant
a.cbegin() const_­iterator const_­cast<​X const&​>(a)​.begin(); constant
a.cend() const_­iterator const_­cast<​X const&​>(a)​.end(); constant
i <=> j strong_­ordering Constraints: X​::​iterator meets the random access iterator requirements. constant
a == b convertible to bool == is an equivalence relation. equal(​a.begin(), a.end(), b.begin(), b.end()) Preconditions: T meets the Cpp17EqualityComparable requirements Constant if a.size() != b.size(), linear otherwise
a != b convertible to bool Equivalent to !(a == b) linear
a.swap(b) void Effects: exchanges the contents of a and b (Note A)
swap(a, b) void Equivalent to a.swap(b) (Note A)
r = a X& Postconditions: r == a. linear
a.size() size_­type distance(​a.begin(), a.end()) constant
a.max_­size() size_­type distance(​begin(), end()) for the largest possible container constant
a.empty() convertible to bool a.begin() == a.end() constant

Those entries marked “(Note A)” or “(Note B)” have linear complexity for array and have constant complexity for all other standard containers.

The member function size() returns the number of elements in the container.

The number of elements is defined by the rules of constructors, inserts, and erases.

begin()returns an iterator referring to the first element in the container.

end()returns an iterator which is the past-the-end value for the container.

If the container is empty, thenbegin() == end().

In the expressions

i == j i != j i < j i <= j i >= j i > j i <=> j i - j

where i and j denote objects of a container's iteratortype, either or both may be replaced by an object of the container'sconst_­iterator type referring to the same element with no change in semantics.

Unless otherwise specified, all containers defined in this clause obtain memory using an allocator (see [allocator.requirements]).

[ Note

:

In particular, containers and iterators do not store references to allocated elements other than through the allocator's pointer type, i.e., as objects of type P orpointer_­traits<P>​::​template rebind<unspecified>, where P is allocator_­traits<allocator_­type>​::​pointer.

end note

]

Copy constructors for these container types obtain an allocator by callingallocator_­traits<allocator_­type>​::​select_­on_­container_­copy_­constructionon the allocator belonging to the container being copied.

Move constructors obtain an allocator by move construction from the allocator belonging to the container being moved.

Such move construction of the allocator shall not exit via an exception.

All other constructors for these container types take aconst allocator_­type& argument.

[ Note

:

If an invocation of a constructor uses the default value of an optional allocator argument, then the allocator type must support value-initialization.

end note

]

A copy of this allocator is used for any memory allocation and element construction performed, by these constructors and by all member functions, during the lifetime of each container object or until the allocator is replaced.

The allocator may be replaced only via assignment orswap().

Allocator replacement is performed by copy assignment, move assignment, or swapping of the allocator only ifallocator_­traits<allocator_­type>​::​propagate_­on_­container_­copy_­assignment​::​value,allocator_­traits<allocator_­type>​::​propagate_­on_­container_­move_­assignment​::​value, or allocator_­traits<allocator_­type>​::​propagate_­on_­container_­swap​::​value is truewithin the implementation of the corresponding container operation.

In all container types defined in this Clause, the member get_­allocator()returns a copy of the allocator used to construct the container or, if that allocator has been replaced, a copy of the most recent replacement.

The expression a.swap(b), for containers a and b of a standard container type other than array, shall exchange the values of a andb without invoking any move, copy, or swap operations on the individual container elements.

Lvalues of any Compare, Pred, or Hash types belonging to a and b shall be swappable and shall be exchanged by calling swapas described in [swappable.requirements].

Ifallocator_­traits<allocator_­type>​::​propagate_­on_­container_­swap​::​value istrue, then lvalues of type allocator_­type shall be swappable and the allocators of a and b shall also be exchanged by calling swap as described in [swappable.requirements].

Otherwise, the allocators shall not be swapped, and the behavior is undefined unless a.get_­allocator() == b.get_­allocator().

Every iterator referring to an element in one container before the swap shall refer to the same element in the other container after the swap.

It is unspecified whether an iterator with value a.end() before the swap will have value b.end() after the swap.

If the iterator type of a container belongs to the bidirectional or random access iterator categories, the container is calledreversibleand meets the additional requirements in Table 74.

Table 74: Reversible container requirements [tab:container.rev.req]

Expression Return type Assertion/note Complexity
pre-/post-condition
X​::​reverse_­iterator iterator type whose value type is T reverse_­iterator<iterator> compile time
X​::​const_­reverse_­iterator constant iterator type whose value type is T reverse_­iterator<const_­iterator> compile time
a.rbegin() reverse_­iterator; const_­reverse_­iterator for constant a reverse_­iterator(end()) constant
a.rend() reverse_­iterator; const_­reverse_­iterator for constant a reverse_­iterator(begin()) constant
a.crbegin() const_­reverse_­iterator const_­cast<X const&>(a).rbegin() constant
a.crend() const_­reverse_­iterator const_­cast<X const&>(a).rend() constant

Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container.

Table 75 lists operations that are provided for some types of containers but not others.

Those containers for which the listed operations are provided shall implement the semantics described in Table 75 unless otherwise stated.

If the iterators passed to lexicographical_­compare_­three_­waymeet the constexpr iterator requirements ([iterator.requirements.general]) then the operations described in Table 75are implemented by constexpr functions.

Table 75: Optional container operations [tab:container.opt]

Expression Return type Operational Assertion/note Complexity
semantics pre-/post-condition
a <=> b synth-three-​way-result​<value_­type> lexicographical_­compare_­three_­way(a.begin(), a.end(), b.begin(), b.end(), synth-three-way) Preconditions: Either <=> is defined for values of type (possibly const) T, or < is defined for values of type (possibly const) T and< is a total ordering relationship. linear

[ Note

:

The algorithm lexicographical_­compare_­three_­wayis defined in [algorithms].

end note

]

All of the containers defined in this Clause and in [basic.string] except arraymeet the additional requirements of an allocator-aware container, as described in Table 76.

Given an allocator type Aand given a container type X having a value_­type identical to Tand an allocator_­type identical to allocator_­traits<A>​::​rebind_­alloc<T>and given an lvalue m of type A, a pointer p of type T*, an expression v of type (possibly const) T, and an rvalue rv of type T, the following terms are defined.

If Xis not allocator-aware, the terms below are defined as if A wereallocator<T> — no allocator object needs to be created and user specializations of allocator<T> are not instantiated:

[ Note

:

A container calls allocator_­traits<A>​::​construct(m, p, args)to construct an element at p using args, with m == get_­allocator().

The default construct in allocator will call ​::​new((void*)p) T(args), but specialized allocators may choose a different definition.

end note

]

In Table 76, X denotes an allocator-aware container class with a value_­type of T using allocator of type A, u denotes a variable,a and b denote non-const lvalues of type X,t denotes an lvalue or a const rvalue of type X, rv denotes a non-const rvalue of type X, and m is a value of type A.

Table 76: Allocator-aware container requirements [tab:container.alloc.req]

Expression Return type Assertion/note Complexity
pre-/post-condition
allocator_­type A Mandates: allocator_­type​::​value_­type is the same as X​::​value_­type. compile time
get_­- allocator() A constant
X() X u; Preconditions: A meets the Cpp17DefaultConstructible requirements. Postconditions: u.empty() returns true,u.get_­allocator() == A() constant
X(m) Postconditions: u.empty() returns true, constant
X u(m); u.get_­allocator() == m
X(t, m) X u(t, m); Preconditions: T is Cpp17CopyInsertable into X. Postconditions: u == t, u.get_­allocator() == m linear
X(rv) X u(rv); Postconditions: u has the same elements as rv had before this construction; the value of u.get_­allocator() is the same as the value of rv.get_­allocator() before this construction. constant
X(rv, m) X u(rv, m); Preconditions: T isCpp17MoveInsertable into X. Postconditions: u has the same elements, or copies of the elements, that rv had before this construction, u.get_­allocator() == m constant if m == rv.get_­allocator(), otherwise linear
a = t X& Preconditions: T isCpp17CopyInsertable into X and Cpp17CopyAssignable. Postconditions: a == t linear
a = rv X& Preconditions: If allocator_­- traits<allocator_­type> ​::​propagate_­on_­container_­- move_­assignment​::​value is false, T isCpp17MoveInsertable into X andCpp17MoveAssignable. Effects: All existing elements of a are either move assigned to or destroyed. Postconditions: a is equal to the value that rv had before this assignment. linear
a.swap(b) void Effects: exchanges the contents of a and b constant

The behavior of certain container member functions and deduction guides depends on whether types qualify as input iterators or allocators.

The extent to which an implementation determines that a type cannot be an input iterator is unspecified, except that as a minimum integral types shall not qualify as input iterators.

Likewise, the extent to which an implementation determines that a type cannot be an allocator is unspecified, except that as a minimum a type A shall not qualify as an allocator unless it meets both of the following conditions: