cplusplus-primer-5ed-notes/part_i/chap3_strings_vectors_and_a...

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 using vector:
#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):

  1. subscripts
  2. 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
  • 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 to toupper and assign the resulting uppercase letter back to into character denoted by it

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's size_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:
      1. concept of an iterator
      1. iterator type defined by an container
      1. 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 to it and to apply dot operator to the result of dereferencing it.
(*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 to end or it will denote the element for which we are looking.