# Half-open interval

• `.begin()` returns an iterator that “points” to the first element
• `.end()` returns an iterator that “points” one past the last element
• They form a half-open interval.
• Remember, iterators are not pointers.

# `.begin()` and `.end()`

```vector<int> v = {11, 22, 33, 44, 55};
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
```
`11 22 33 44 55 `

or:

```vector<int> v = {11, 22, 33, 44, 55};
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
```
`11 22 33 44 55 `

`++it` is probably faster than `it++`.

# `const`

Why does this fail?

```class Foo {
int sum() const {
int total = 0;
for (vector<int>::iterator it = data.begin(); it != data.end(); ++it)
total += *it;
}
vector<int> data;
};
```
```c.cc: In member function 'int main()::Foo::sum() const':
c.cc:4:51: error: conversion from 'std::vector<int>::const_iterator {aka
__gnu_cxx::__normal_iterator<const int*, std::vector<int> >}' to non-scalar
type 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*,
std::vector<int> >}' requested
```

# `const`

• `.sum()` is a `const` method.
• Therefore, inside `.sum()`, `data` is a `const vector<int>`.
• Let that sink in for a moment.
• How is a `const` method implemented, anyway?
• It’s not that the compiler checks for changes to member data inside a `const` method.
• Instead, the compiler simply regards all data members as `const` when compiling a `const` method.
• Therefore, `data.begin()` and `data.end()` return iterators of type `const_iterator`, not type `iterator`.
• You can’t assign `const_iterator` to `iterator`.

# Restate the problem

This is the same problem:

```const vector<int> v = {11, 22, 33, 44, 55};
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
```
```c.cc: In function 'int main()':
c.cc:2:40: error: conversion from 'std::vector<int>::const_iterator {aka
__gnu_cxx::__normal_iterator<const int*, std::vector<int> >}' to non-scalar
type 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*,
std::vector<int> >}' requested
```

# Solution #1

One solution—use the correct type:

```const vector<int> v = {11, 22, 33, 44, 55};
for (vector<int>::const_iterator it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
```
`11 22 33 44 55 `

# Solution #2

A better solution—let `auto` figure it out:

```const vector<int> v = {11, 22, 33, 44, 55};
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << ' ';
```
`11 22 33 44 55 `

# Solution #3

The best solution—avoid all of this:

```const vector<int> v = {11, 22, 33, 44, 55};
for (auto val : v)
cout << val << ' ';
```
`11 22 33 44 55 `

# `.cbegin()` and `.cend()`

• `.begin()` is an overloaded method. It returns a `const_iterator` if the object is `const`, `iterator` otherwise.
• `.end()` is an overloaded method. It returns a `const_iterator` if the object is `const`, `iterator` otherwise.
• `.cbegin()`: like `.begin()`, but always returns `const_iterator`
• `.cend()`: like `.end()`, but always returns `const_iterator`

```vector<int> v = {11, 22, 33, 44, 55};
for (auto it = v.cbegin(); it != v.cend(); ++it)
cout << *it << ' ';
```
`11 22 33 44 55 `

# `.rbegin()` and `.rend()`

• `.rbegin()`: like `.begin()`, but goes the other way
• `.rend()`: like `.end()`, but goes the other way
• `.crbegin()`: like `.cbegin()`, but goes the other way
• `.crend()`: like `.cend()`, but goes the other way

```vector<int> v = {11, 22, 33, 44, 55};
for (auto it = v.rbegin(); it != v.rend(); ++it)
cout << *it << ' ';
```
`55 44 33 22 11 `
```vector<int> v = {11, 22, 33, 44, 55};
for (auto it = v.crbegin(); it != v.crend(); ++it)
cout << *it << ' ';
```
`55 44 33 22 11 `

# Don’t get too excited

• Not all containers have the reversed versions.
• For example, `forward_list`, as a singly-linked list, doesn’t have reverse iterators.
• For some containers, `iterator` and `const_iterator` are the same.
• A `set` has inherently-constant iterators, because it’s in order. If you could change the values via iterators, then it wouldn’t be in order any more.
• An `unordered_set`, a hash, has its own special order, and changing the values in place would be bad.

# Plain old data types:

```int a[] = {11, 22, 33, 44, 55};
for (auto it = a.begin(); it != a.end(); ++it)
cout << *it << ' ';
```
```c.cc: In function 'int main()':
c.cc:2:18: error: request for member 'begin' in 'a', which is of non-class type
'int [5]'
c.cc:2:35: error: request for member 'end' in 'a', which is of non-class type
'int [5]'
```

That failed miserably. Perhaps it’s because arrays are not objects.

# Free functions

Fortunately, there exist `begin()` and `end()` free functions (not methods).

```int a[] = {11, 22, 33, 44, 55};
for (auto it = begin(a); it != end(a); ++it)
cout << *it << ' ';
```
`11 22 33 44 55 `

These work for objects, as well:

```set<int> s = {11, 22, 33, 44, 55};
for (auto it = begin(s); it != end(s); ++it)
cout << *it << ' ';
```
`11 22 33 44 55 `

What use is that? Generality for the sake of generality?

# for loop

Consider any for loop:

```forward_list<int> fl = {11,22,33,44,55};
for (double v : fl)
cout << v << ' ';
```
`11 22 33 44 55 `

The compiler turns this into:

```forward_list<int> fl = {11,22,33,44,55};
const auto toofar = end(fl);
for (auto it = begin(fl); it != toofar; ++it) {
double v = *it;
cout << v << ' ';
}
```
`11 22 33 44 55 `

Which works for any container type, even C-style arrays.

User: Guest

Check: HTML CSS
Edit History Source

Modified: 2018-04-24T16:50

Apply to CSU | Contact CSU | Disclaimer | Equal Opportunity
Colorado State University, Fort Collins, CO 80523 USA