The deque class implements a double-ended queue and, in its
STL incarnation, has an interface which is very similar to that of the
vector class. The major conceptual difference is that a deque provides
fast insertion and deletion at both ends.
Default Constructor
- deque<T> d;
- Construct an empty deque d which can hold values of type
T.
Copy Constructor
There is, of course, only one copy constructor, but there are two
syntactic forms that invoke it, and both are shown.
- deque<T> d(otherDeque);
- Construct d as a copy of otherDeque, whose
component type must be T. The copy has the same size as the
original.
- deque<T> d = otherDeque;
- Copy constructor (alternate usage syntax).
Other Constructors
- deque<T> d(num);
- Construct a deque d of size num containing
num values, each equal to the default value of type
T.
- deque<T> d(num, val);
- Construct a deque d of size num containing
num values, each equal to val, which must be of
type T, and which may be supplied by a variable, a literal
or named constant, or a function call.
- deque<T> d(inIterBegin, inIterEnd);
- Construct d containing values from the range
[inIterBegin,inIterEnd) in another (not necessarily deque)
container, but whose component type is the same as the component type
of d.
Destructor
- d.~deque<T>()
- Destroy all components of d and free the associated
memory.
Assignment operator
- d1 = d2
- Assign d2 to d1, and return the common value.
The deque on the left of an assignment receives the values and size
of the one on the right.
Relational operators
Deques are compared in the "lexicographic ordering" sense. This
essentially means that the two deques are compared by comparing their
values pairwise, starting at the beginning, with each comparison
looking at two values in corresponding positions, until a determination
of the relationship between the two deques can be made. Only deques of
the same component type can be compared of course, and the ==
and < operators must be defined for the component type.
- d1 == d2
- Return true if d1 and d2 have the same
component type and the same size, and the components in each pair of
corresponding locations have the same value; otherwise return
false.
- d1 != d2
- Return true if d1==d2 returns false;
otherwise return false.
- d1 < d2
- Return true if, in the pairwise comparison of values
from d1 and d2, in the first pair in which the two
values differ, the one from d1 is less than the one from
d2; otherwise return false.
- d1 <= d2
- Return true if either d1<d2 or
d1==d2 is true; otherwise return
false.
- d1 > d2
- Return true if d2<d1 is true;
otherwise return false.
- d1 >= d2
- Return true if either d1>d2 or
d1==d2 is true, otherwise return
false.
operator[ ]
- d[i]
- Return a reference (or const_reference) to the
component of d with index i. (Index values start at
0, and there is no checking for an index out of bounds.)
Each of the member functions in this section has both a
const and a non-const version.
- d.at(i)
- Return a reference (or const_reference) to the
component of d with index i. (Throws an
out_of_range exception if i is not a valid index
for d.)
- d.front()
- Return a reference (or const_reference) to the
first component of d.
- d.back()
- Return a reference (or const_reference) to the
last component of d.
- d.begin()
- Return an iterator (or const_iterator) pointing
to the first component of d.
- d.end()
- Return an iterator (or const_iterator) pointing
to one-past-the-last component of d.
- d.rbegin()
- Return a reverse_iterator (or
const_reverse_iterator) pointing to the last component of
d.
- d.rend()
- Return a reverse_iterator (or
const_reverse_iterator) pointing to one-before-the-first
component of d.
- d.max_size()
- Return a value of type size_type giving the maximum
possible size of d, which will depend on the size of the
component type T of the deque object, and the amount of
available memory.
- d.size()
- Return a value of type size_type giving the number of
values currently in d.
- d.empty()
- Return true if d is empty (contains zero
values); otherwise return false.
- d.assign(num, val)
- Assign num copies of val to d,
overwriting the entire previous contents of d.
- d.assign(inIterBegin, inIterEnd)
- Assign to d the values from the range
[inIterBegin,inIterEnd) in another (not necessarily deque)
container, but whose values are also of type T, overwriting
the entire previous contents of d.
- d.insert(iter, val)
- Insert val into d immediately before the value
pointed to by iter, and return an iterator pointing
at the new component with value val.
- d.insert(iter, num, val)
- Insert num copies of val into d,
immediately before the value pointed to by iter.
- d.insert(iter, inIterBegin, inIterEnd)
- Insert into d, immediately before the value pointed to
by iter, values from the range
[inIterBegin,inIterEnd) in another (not necessarily deque)
container, but whose values must be of the same type as the values of
d.
- d.push_back(val)
- Add val to the end of d, increasing the size of
d by one.
- d.push_front(val)
- Add val to the front of d, increasing the size
of d by one.
- d.clear()
- Delete all values of d. The size of d is
reduced to zero.
- d.erase(iter)
- Delete the value of d pointed to by iter and
return an iterator pointing at the following value, or to
one-past-the-last if the value deleted was the last one. The size of
d is reduced by one.
- d.erase(iterBegin, iterEnd)
- Delete all values of d from the range
[iterBegin,iterEnd) and return iterEnd. The size of
d is reduced by iterEnd-iterBegin (a value of type
difference_type).
- d.pop_back()
- Delete the last value of d. The size of d is
reduced by one.
- d.pop_front()
- Delete the first value of d. The size of d is
reduced by one.
- d.resize(num)
- Change size of d to num. (If d must be
lengthened, default values of its component type are added to the end
of d. If d is shortened, values at the end are
lost.)
- d.resize(num, val)
- Change size of d to num. (If d must be
lengthened, copies of val are added to the end of
d. If d is shortened, values at the end are lost,
and the value of val is not used.)
- d.swap(otherDeque)
- Exchange values in d with those in otherDeque.
The sizes are swapped as well.
- d.getallocator()
- Return the allocator of d. (This is possibly the most
infrequently used of all member functions of the deque class.)
- Differences in the use of d[i] and d.at(i)
- The "safer" choice to access an element of d via an
index i is d.at(i) rather than d[i]. This
is because d.at(i) throws an out_of_range exception
if i is not a valid index value for d, unlike
d[i], which behaves just as if d were an ordinary
array, and thus does not give you any warning if your index goes out
of bounds. If it does go out of bounds, you may get a run-time error,
or your program may simply use whatever is stored at the invalid
location as though it were a piece of valid data.
- Danger of invalidation of iterators, references and pointers
- Although it may not be strictly true in all situations, it is
probably safest to assume that any member function that inserts or
removes values or changes the size of a deque will invalidate any
iterators, references or pointers already associated with values of
that deque.
- Implementation
- Standard C++ does not say how the STL containers and algorithms
must be implemented. It does, however, state certain constraints,
such as complexity constraints, to which each implementation must
adhere. Thus it is much better to base your programs on the STL's
performance guarantees, rather than upon any assumption about how a
particular feature, like the deque class, may be
implemented.
- Some performance and usage issues
-
Deques tend to be useful in situations where order of components,
compact storage, and fast insertions and deletions at the ends are
important. They can be used to implement any FIFO (First In First
Out) structure, though a queue should be used if there must be
strict FIFO behavior with no direct access by numeric index
permitted. If fast insertions near the middle need to be made, a
list is the better choice.
The deque is one of the three "sequential" container classes in
the STL (the vector and the list are the other two). Usually, if
you're wondering about using a deque, the choice will be between
using a deque or using a vector, since they have so much in common.
Element access tends to be a bit faster in vectors, though both
vectors and deques offer constant-time access to elements (from a
big-Oh perspective). If there are to be many insertions and
deletions at the ends, and particularly at the front, the deque
would be a better choice. In general, though, when an array-like
object which can grow and shrink dynamically is needed, the vector
tends to be the container of choice.
There are two groups of sample programs. The first group involves
only STL deques and generic C++, while the second group involves other
STL features in addition to deques. The programs should be studied in
the sequence given, since the description of each new sample program in
the sequence mentions only the new features illustrated for the first
time in that particular program, and features seen in earlier sample
programs will continue to reappear in later programs.
All of the programs have been compiled and run successfully under
Microsoft Visual Studio .NET 2005, unless otherwise noted.
Programs involving only deques (and generic C++)
- deque01.cpp | Windows_executable | program_output (text)
- Illustrates deque constructors, accessing deque values with
d[i], the typedef deque<T>::size_type, and
the member functions size() and empty(). Also
illustrates how ordinary array pointers can be used, in certain
situations, in the same way that STL iterators are used.
- deque02.cpp | Windows_executable | program_output (text)
- Illustrates the similarities and differences between
d[i] and d.at(i).
- deque03.cpp | Windows_executable | program_output (text)
- Illustrates member function max_size(), and how the
maximum size for a deque object depends on the size of its component
type.
- deque04.cpp | Windows_executable | program_output (text)
- Illustrates push_back() and push_front().
- deque05.cpp | Windows_executable | program_output (text)
- Illustrates typical uses of the default (random-access) iterator
for the deque class, shows additional uses of member functions
begin() and end(), and also shows the use of
operators =, +, -, ++, --, != and * with
deque class iterators.
- deque06.cpp | Windows_executable | program_output (text)
- Illustrates the default (random-access) deque class iterator in
additional situations, and shows the use of operators ->,
[ ], <, >, <=, >=,
+=, -= and == with deque class
iterators.
- deque07.cpp | Windows_executable | program_output (text)
- Illustrates reverse iterators for the deque class, as well as
member functions rbegin() and rend().
- deque08.cpp | Windows_executable | program_output (text)
- Illustrates a typical use of a const iterator.
- deque09.cpp | Windows_executable | program_output (text)
- Illustrates member functions front() and
back().
- deque10.cpp | Windows_executable | program_output (text)
- Illustrates the overloaded assignment operator = and the
assign() member function.
- deque11.cpp | Windows_executable | program_output (text)
- Illustrates the insert() member function.
- deque12.cpp | Windows_executable | program_output (text)
- Illustrates clear(), erase(),
pop_back() and pop_front() member functions.
- deque13.cpp | Windows_executable | program_output (text)
- Illustrates the resize() member function.
- deque14.cpp | Windows_executable | program_output (text)
- Illustrates the swap() member function.
Programs involving additional deque features and deques in
combination with other STL features
- deque_a.cpp | Windows_executable | program_output (text)
- Illustrates the use of stream iterators and the copy
algorithm for I/O of deque values.
- deque_b.cpp | Windows_executable | program_output (text)
- Illustrates how to display the name of the underlying type
represented by each typedef defined by a deque class.
- deque_c.cpp | Windows_executable | program_output (text)
- Illustrates initialization of a deque with values from non-deque
containers (in this case, a vector and a list).
For enhanced readability in each of the prototypes given below, each
parameter in each parameter list appears on a separate line. Also, some
formatting liberties are taken, in the interest of greater readability.
For example, rather than aligning all prototypes at the left margin,
const and non-const versions of a member function are
aligned in such a way as to allow the reader to more easily compare the
two visually.
Template specification for the deque class
template<class T,
class Allocator = allocator<T> >
class deque { ... }
Constructors
explicit deque(const Allocator& a = Allocator());
explicit deque(size_type num,
const T& val = T(),
const Allocator& a = Allocator());
template<class InIterator>
deque(InIterator inIterBegin,
InIterator inIterEnd,
const Allocator& a = Allocator());
Copy Constructor
deque(const deque<T, Allocator>& otherDeque);
Destructor
~deque();
assign
void assign(size_type num,
const T& val);
template<class InIterator>
void assign(InIterator inIterBegin,
InIterator inIterEnd);
at
reference at(size_type i);
const_reference at(size_type i) const;
back
reference back();
const_reference back() const;
begin
iterator begin();
const_iterator begin() const;
clear
void clear();
empty
bool empty() const;
end
iterator end();
const_iterator end() const;
erase
iterator erase(iterator iter);
iterator erase(iterator iterBegin,
iterator iterEnd);
front
reference front();
const_reference front() const;
get_allocator
allocator_type get_allocator() const;
insert
iterator insert(iterator iter,
const T& val);
void insert(iterator iter,
size_type num,
const T& val);
template<class InIterator>
void insert(iterator iter,
InIterator inIterBegin,
InIterator inIterEnd);
max_size
size_type max_size() const;
operator[ ]
reference operator[](size_type i);
const_reference operator[](size_type i) const;
pop_back
void pop_back();
pop_front
void pop_front();
push_back
void push_back(const T& val);
push_front
void push_front(const T& val);
rbegin
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
rend
reverse_iterator rend();
const_reverse_iterator rend() const;
resize
void resize(size_type num,
T val = T());
size
size_type size() const;
swap
void swap(deque<T, Allocator>& otherDeque);