8.1 KiB
Chapter 3. Strings, Vectors, and Arrays
3.3 Library vector Type
- vector = collection of objs (all have same type)
- vector is a container (it "contains" other objects). Detail of containers are in Part II
- Include correct header and
using
declaration before usingvector
:
#include <vector>
using std::vector;
- vector is a class template (Details are introduced in Chapter 13)
- Template are not functions or classes. But can be used to generating classes or functions.
- Process of creating classes/func from template is instantiation
- Specify which class to instantiate by
template_name<> obj_name
(C++11 standard)
vector<int> ivec; // ivec holds objects of type int
vector<Sales_item> Sales_vec; // holds Sales_items
vector<vector<string>> file; // vector whose elements are vectors
Note:
vector
is template, not a type.- Types generated from
vector
must include element type (e.g.vector<int>
)
???
3.4 Introducing Iterators
Two ways of access containers (i.e. vector):
- subscripts
- iterators
All containers from library have iterators, but not all of them support subscript operator.
- iterator provide indirect access like pointers
- iterator can be valid/invalid
3.4.1 Using Iterators
- Containers have members to return iterator:
begin
&end
begin
returns an iterator denotes the 1st element:end
return an iterator positioned "one past the end" of container (i.e. it's nonexistent element "off the end")- iterator returned by
end
often referred to off-the-end iterator or end iterator
- iterator returned by
- If container is empty:
begin
end
's iterator are same
// the compiler determines the type of b and e; see § 2.5.2 (p. 68)
// b denotes the first element and e denotes one past the last element in v
auto b = v.begin(), e = v.end(); // b and e have the same type
For best practice:
- Normally, we don't (want to) know the precise type of iterator. We Hence use
auto
to let compiler decide.
Iterator Operations
operator | Description |
---|---|
*iter |
Returns a reference to the element denoted by iterator |
iter->mem |
Dereference iter and fetches the member named mem from the underlying element. Equivalent to (*iter).mem |
++iter |
Increments iter to refer to next element |
--iter |
Decrements iter to refer to previous element |
iter1 == iter2 ; iter1 != iter2 |
Compares 2 iterators, they are equal if denoting same element or they are end iterator of same container |
- Here
*iter
return a reference is actually deference the iterator (like pointer's operation).
Following code transfer the first char to upper letter:
string s("some string");
if (s.begin() != s.end()) { // make sure s is not empty
auto it = s.begin(); // it denotes the first character in s
*it = toupper(*it); // make that character uppercase, dereference it via `*it`
}
- We dereference
it
to pass the current char totoupper
and assign the resulting uppercase letter back to into character denoted byit
Moving Iterators from One Element to Another
++/--
in/decrement operators are used to move iterators from one element to next.- end-iterator does not denote an element, it cannot be incremented & dereferenced.
// process characters in s until we run out of characters or we hit a whitespace
for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
*it = toupper(*it); // capitalize the current character
- This code stop at whitespace
Key Concept: Generic Programming
- C++ programmers use
!=
as habit - Only few library types have subscript operator, all library containers have iterators that defined
==
&!=
. Most of them does not have<
Iterator Types
- We generally don't need to know the precise type of an iterator (like we use
auto
for vector'ssize_type
member) - Iterators from library types have
iterator
&const_iterator
type
vector<int>::iterator it; // it can read and write vector<int> elements
string::iterator it2; // it2 can read and write characters in a string
vector<int>::const_iterator it3; // it3 can read but not write elements
string::const_iterator it4; // it4 can read but not write characters
Terminology confusion: Iterators and Iterator Types
- "iterator" refers to 3 entities:
-
- concept of an iterator
-
iterator
type defined by an container
-
- object
-
- Every container class defines a type named
iterator
; it supports actions
begin
and end
Operation
If object returned by begin
& end
are const
, then type returned by begin
/end
are const
vector<int> v;
const vector<int> cv; // cv is a vector with constant integer
auto it1 = v.begin(); // it1 has type vector<int>::iterator
auto it2 = cv.begin(); // it2 has type vector<int>::const_iterator
As shown above, the type are varying. C++11 gave cbegin
& cend
functions to specify type
auto it3 = v.cbegin(); // it3 has type vector<int>::const_iterator
Combining Dereference and Member Access
Correct way of dereference iterator and access members:
(xx)
for(*it)
is required. It means apply dereference operator toit
and to apply dot operator to the result of dereferencingit
.
(*it).empty()
- Incorrect usage:
- Iterator has no members
(*it).empty() // dereferences it and calls the member empty on the resulting object
*it.empty() // error: attempts to fetch the member named empty from it
// but it is an iterator and has no member named empty
Simplified dereference & member access:
->
operator;
// print each line in text up to the first blank line
for (auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
cout << *it << endl;
Currently remember loops that use iterators should not add elements to the container to which the iterator refer
3.4.2 Iterator Arithmetic
Operations suppoted by vector and string Iterators
Operator | Description |
---|---|
iter +/- n |
generate a iterator that many elements forward/backward within container |
iter += n or iter -= n |
Compound-assignment for iterator addition/subtraction |
iter1 - iter2 |
yields the number |
> , >= , < , <= |
A iterator < other means it appears before |
// compute an iterator to the element closest to the midpoint of vi
auto mid= vi.begin() + vi.size() / 2;
if (it < mid)
// process elements in the first half of vi
??? Skip ???
Using Iterator Arithmetic
Binary search using iterator arithmetic
// text must be sorted
// beg and end will denote the range we're searching
auto beg = text.begin(), end = text.end();
auto mid = text.begin() + (end - beg)/2; // original midpoint
// while there are still elements to look at and we haven't yet found sought
while (mid != end && *mid != sought) {
if (sought < *mid) // is the element we want in the first half?
end = mid; // if so, adjust the range to ignore the second half
else // the element we want is in the second half
beg = mid + 1; // start looking with the element just after mid
mid= beg + (end - beg)/2; // new midpoint
}
- At end of
while
,mid
will be equal toend
or it will denote the element for which we are looking.