Chapter 9. Sequential Containers
Last updated
Last updated
A container holds a collection fo objects of a specified type. The sequential containers let the programmer control the order in which the elements are stored and accessed.
There are few rules of thumb that apply to selecting which container to use:
Unless you have a reason to use another container, use a vector
.
If your program has lots of small elements and space overhead matters, don't use list
or forward_list
.
If the program requires random access to elements, use a vector
or a deque
.
If the program needs to insert or delete elements in the middle of the container, use a list
or forward_list
.
If the program needs to insert or delete elements at the front and the back, but not in the middle, use a deque
.
As with the containers, iterators have a common interface: If an iterator provides an operation, then the operation is supported in the same way for each iterator that supplies that operation.
An iterator range is denoted by a pair of iterators each of which refers to an element, or to one past the last element, in the same container. These two iterators, often referred to as begin
and end
, or as first
end last
, mark a range of elements from the container.
This element range is called a left-inclusive interval. The standard mathematical notion for such a range is [begin, end)
.
Each container defines several types, three of these container-defined types: size_type
, iterator
, and const_iterator
.
The begin and end operations yield iterators that refer to the first and one past the last element in the container.
When we initialise a container as a copy of another container, the container type and element type of both containers must be identical.
Under the new standard, we can list initialise a container:
We can also initialise the sequential containers from a size and an element initialiser:
The constructors that take a size are valid only for sequential containers; they are not supported for the associative containers.
When we define an array, in addition to specifying the element type, we also specify the container size:
The assignment operator replace the entire range of elements int eh left-hand container with copies of the elements from the right-hand operand.
The assignment operator requires that the left-hand and right-hand operands have the same type. It copies all the elements from the right-hand operand into left-hand operand.
The swap operation exchanges the contents of two containers of the same type.
In the new library, the containers offer both a member and nonmember version of swap. Earlier versions of the library defined only the member version of swap. The nonmember swap is of most importance in generic programs.
The size
member returns the number of elements in the container; empty
returns a bool that is true if size is zero and false otherwise; and max_size
returns a number that is greater than or equal to the number of elements a container of that type can contain.
Comparing two containers performs a pairwise comparison of the elements:
If both containers are the same size and all the elements are equal, then the two containers are equal; otherwise, they are unequal.
If the containers have different sizes but every element of the smaller one is equal to the corresponding element of the larger one, then the smaller one is less than the other.
If neither container is an initial subsequence of the other, then the comparison depend s on comparing the first unequal elements.
We can use a relational operator to compare two containers only if the appropriate comparison operator is defined for the element type.
In the call to emplace_back
, that object is crated directly in space managed by the container The call to push_back
creates a local temporary object that is pushed onto the container.
The members that access elements in a container return references. If the container is a const object, the return is a reference to const. If the container is not const, the return is an ordinary reference that we can use to change the value of the fetched element.
Operations that add or remove elements from a container can invalidate pointers, references, or iterators to container elements. An invalidated pointer, reference, or iterator is one that no longer denotes an element.
After an operation that adds elements to a container:
Iterators, pointers, and references to a vector
or string
are invalid if the container was reallocated.
Iterators, pointers, and references to a deque
are invalid if we add elements anywhere but at the front or back.
Iterators, pointers, and references to a list
or forward_list
remain valid.
After we remove an element:
All other iterators, references, or pointers to a list or forward_list remain valid.
All other iterators, references, or pointers to a deque
are invalidated if the removed elements are anywhere but the front or back.
All other iterators, references, or pointers to a vector
or string
remain valid for elements before the removal point.
To support fast random access, vector
elements are stored contiguously, each element is adjacent to the previous element.
When they have to get new memory, vector
and string
implementations typically allocate capacity beyond what is immediately needed. The container holds this storage in reserve and uses it to allocate new elements as they are added. reserve
does not change the number of elements in the container; it affects only how much memory the vector
preallocates.
A call to reserve
changes the capacity of the vector
only if the requested space exceeds the current capacity. A call to reserve
will never reduce the amount of space that the container uses.
it is important to understand the difference between capacity
and size
. The size of a container is the number of elements it already holds; its capacity
is how many elements it can hold before more space must be allocated.
The assign
and append
functions have no need to specify what part of the string is changed: assign
is always replaces the entire contents of the string
and append always adds to the end of the string
.
s.compare
returns zero or a positive or negative value depending on whether s is equal to, greater than, or less than the string formed from the given arguments.
If the string can't be converted to a number, these functions throw an invalid_argument
exception. If the conversion generates a value that can't be represented, they throw out_of_range
.
In addition to the sequential containers, the library defines three sequential container adaptors: stack
, queue
, and priority_queue
.
Each adaptor defines two constructor: the default constructor that creates an empty object, and a constructor that takes a container and initialises the adaptor by copying the given container.
By default both stack
and queue
are implemented in terms of deque
, and a priority_queue
is implemented on a vector
.
The stack type is defined in the stack
header.
The queue
and priority_queue
adaptors are defined in the queue
header.
A priority_queue
lets us establish a priority among the elements held in the queue.
Sequential Container Types
Description
vector
Flexible-size array.
deque
Double-ended queue.
list
Doubly lined list.
forward_list
Singly linked list.
array
Fixed-size array.
string
A specialised container, similar to vector, that contains characters
Operation
Description
C c;
Default constructor.
C c1(c2);
c1 is copy from c2.
C c1 = c2;
c1 is copy from c2.
C c{a, b, c};
c is a copy of the elements in the initialiser list.
C c = {a, b, c};
c is a copy of the elements in the initialiser list.
C c = (b, e);
c is a copy of the elements in the range denoted by iterators b end e.
C seq(n);
seq has n value-initialised element; this constructor is explicit.
C seq(n, t);
seq has n elements with value t.
Container Assignment Operations
Description
c1 = c2;
Replace the elements in c1 with copies of the elements in c2.
c = {a, b, c};
Replace the elements in c1 with copies of the elements in the initialiser list.
swap(c1, c2);
Exchanges element in c1 with those in c2.
c1.swap(c2);
seq.assign(b, e);
Replaces elements in seq with those in the range denoted by iterators be and e.
seq.assign(il);
Replaces the elements in seq with those in the initialiser list il.
seq.assign(n, t);
Replaces the elements in seq with n elements with value t.
Operations That Add Elements to a Sequential Container
Description
c.push_back(t);
Creates an element with value t or constructed from args at the end of c.
c.emplace_back(args);
c.push_front(t);
Creates an element with value t or constructed from args on the front of c.
c.emplace_front(args);
c.insert(p, t);
Create an element with value t or constructed from args before the element denoted by iterator p.
c.emplace(p, args);
c.insert(p, n, t);
Inserts n elements with value t before the element denoted by iterator p.
c.insert(p, b, e);
Inserts the elements from the range denoted by iterators b and e before the element denoted by iterator p.
c.insert(p, il);
il is a braced list of element values.
Operations to Access Elements in a Sequential Container
Description
c.back();
Returns a reference to the last element in c.
c.front();
Returns a reference to the first element in c.
c[n];
Returns a reference to the element indexed by the unsigned integral value n.
c.at(n);
Returns a reference to the element indexed by n.
erase Operations on Sequential Containers
Description
c.pop_back();
Removes last element in c.
c.pop_front();
Removes first element in c.
c.erase(p);
Removes the element denoted by the iterator p.
c.erase(b, e);
Removes the range of elements denoted by the iterators b and e.
c.clear();
Removes all the elements in c.
Operations to Insert or Remove Elements in a forward_list
Description
lst.before_begin();
Iterator denoting the nonexistent element just before the beginning of the list
lst.cbefore_begin();
lst.insert_after(p, t);
Inserts element after the one denoted by iterator p. t is an object.
lst.insert_after(p, n, t);
n is a count.
lst.insert_after(p, b, e);
b and e are iterators denoting a range.
lst.insert_after(p, il);
il is a braced list.
emplace_after(p, args);
Uses args to construct an element after the one denoted by iterator p.
lst.erase_after(p);
Removes the element after the one denoted by iterator p or the range of elements from the one after the iterator b up to but not including the one denoted by e.
lst.erase_after(b, e);
Sequential Size Operations
Description
c.resize(n);
Resize c so that it has n elements.
c.resize(n, t);
Resize c to have n elements.
Container Size Management
Description
c.shrink_to_fit();
Request to reduce capacity() to equal size().
c.capacity();
Number of elements c can have before reallocation is necessary.
c.reserve(n);
Allocate space for at least n elements.
Additional Operation of strings
Description
string s(cp, n);
s is a copy of the first n characters in the array to which cp points.
string s(s2, pos2);
s is a copy of the characters in the string s2 starting at the index pos2.
string s(s2, pos2, len2);
s is a copy of len2 characters from s2 starting at the index pos2.
s.substr(pos, n);
Return a string containing n characters from s starting at pos.
Operations to Modify strings
Description
s.insert(pos, args);
Insert characters specified by args before pos.
s.erase(pos, len);
Remove len characters starting at position pos.
s.assign(args);
Replace characters in s according to args.
s.append(args);
Append args to s.
s.replace(range, args);
Remove range of characters from s and replace them with the characters formed by args.
string Search Operations
Description
s.find(args);
Find the first occurrence of args in s.
s.rfind(args);
Find the last occurrence of args in s.
s.find_first_of(args);
Find the first occurrence of any character from args in s.
s.find_last_of(args);
Find the last occurrence of any character from args in s.
s.find_first_not_of(args);
Find the first character in s that is not in args.
s.find_last_not_of(args);
Find the last character in s that is not in args.
Possible Arguments to s.compare
Description
s2
Compare s to s2.
pos1, n1, s2
Compares n1 characters starting at pos1 from s to s2.
pos1, n1, s2, pos2, n2
Compares n1 characters starting at pos1 from s the n2.
cp
Compares s to the null-terminated array pointed to by cp.
pos1, n1, cp
Compares n1 characters starting at pos1 from s to cp.
pos1, n1, cp, n2
Compares n1 characters starting at pos1 from s to n2 characters starting from the pointer cp.
Conversions between strings and Numbers
Description
to_string(val);
Overloaded functions returning the string representation of val.
stoi(s, p, b);
Return the initial substring of s that has numeric content as an int, long, unsigned long, long long, unsigned long long.
stol(s, p, b);
stoul(s, p, b);
stoll(s, p, b);
stoull(s, p, b);
stof(s, p);
Return the initial numeric substring in s as a float, double, or long double.
stod(s, p);
stold(s, p);
Operations and Types Common to the Container Adaptors
Description
size_type
Type large enough to hold the size of the largest object of this type.
value_type
Element type.
container_type
Type of the underlying container on which the adaptor is implemented.
A a;
Create a new empty adaptor named a.
A a(c);
Create a new adaptor named a with a copy of the container c.
relation operators
Each adaptor supports all the relational operators: ==, !=, <, <=, >, >=.
a.empty();
false if a has any elements, true otherwise.
a.size();
Number of elements in a.
swap(a, b);
Swaps the contents of a and b.
a.swap(b);
Stack Operations
Description
s.pop();
Removes, but does not return, the top element from the stack.
s.pus(item);
Creates a new top element on the stack by copying or removing item, or by constructing the element from args.
s.emplace(args);
s.top()
Returns, but does not remove, the top element on the stack.
queue, priority_queue Operations
Description
q.pop();
Removes, but does not return, the front element or highest-priority element from the queue or priority_queue, respectively.
q.front();
Returns, but does not remove, the front or back element of q.
q.back();
Valid only for queue.
q.top();
Returns, but does not remove, the highest-priority element, valid only for priority_queue.
q.push(item);
Create an element with value item or constructed from args at the end of the queue or inits appropriate position in priority_queue.
q.emplace(args);