Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 11: Loops

A loop statement executes a group of statements repeatedly until a condition is met. There are 3 types of primitive loops in C++: for, while, and do...while.

Section 11.1: Range-Based For

Version ≥ C++11

for loops can be used to iterate over the elements of a iterator-based range, without using a numeric index or directly accessing the iterators:

vector<float> v = {0.4f, 12.5f, 16.234f};

for(auto val: v)

{

std::cout << val << " ";

}

std::cout << std::endl;

This will iterate over every element in v, with val getting the value of the current element. The following statement:

for (for-range-declaration : for-range-initializer ) statement

is equivalent to:

{

auto&& __range = for-range-initializer; auto __begin = begin-expr, __end = end-expr; for (; __begin != __end; ++__begin) {

for-range-declaration = *__begin; statement

}

}

Version ≥ C++17

{

auto&& __range = for-range-initializer; auto __begin = begin-expr;

auto __end = end-expr; // end is allowed to be a different type than begin in C++17 for (; __begin != __end; ++__begin) {

for-range-declaration = *__begin; statement

}

}

This change was introduced for the planned support of Ranges TS in C++20.

In this case, our loop is equivalent to:

{

auto&&

__range

= v;

 

auto __begin

=

v.begin(),

__end = v.end();

for (;

__begin

!= __end; ++__begin) {

auto val

=

*__begin;

 

std::cout << val << "

";

GoalKicker.com – C++ Notes for Professionals

44

}

}

Note that auto val declares a value type, which will be a copy of a value stored in the range (we are copy-initializing it from the iterator as we go). If the values stored in the range are expensive to copy, you may want to use const auto &val. You are also not required to use auto; you can use an appropriate typename, so long as it is implicitly convertible from the range's value type.

If you need access to the iterator, range-based for cannot help you (not without some e ort, at least).

If you wish to reference it, you may do so:

vector<float> v = {0.4f, 12.5f, 16.234f};

for(float &val: v)

{

std::cout << val << " ";

}

You could iterate on const reference if you have const container:

const vector<float> v = {0.4f, 12.5f, 16.234f};

for(const float &val: v)

{

std::cout << val << " ";

}

One would use forwarding references when the sequence iterator returns a proxy object and you need to operate on that object in a non-const way. Note: it will most likely confuse readers of your code.

vector<bool> v(10);

for(auto&& val: v)

{

val = true;

}

The "range" type provided to range-based for can be one of the following:

Language arrays:

float arr[] = {0.4f, 12.5f, 16.234f};

for(auto val: arr)

{

std::cout << val << " ";

}

Note that allocating a dynamic array does not count:

float *arr = new float[3]{0.4f, 12.5f, 16.234f};

for(auto val: arr) //Compile error.

{

std::cout << val << " ";

}

GoalKicker.com – C++ Notes for Professionals

45

Any type which has member functions begin() and end(), which return iterators to the elements of the type. The standard library containers qualify, but user-defined types can be used as well:

struct Rng

{

float arr[3];

// pointers are iterators

const float* begin() const {return &arr[0];} const float* end() const {return &arr[3];}

float*

begin() {return

&arr[0];}

float*

end() {return

&arr[3];}

};

int main()

{

Rng rng = {{0.4f, 12.5f, 16.234f}};

for(auto val: rng)

{

std::cout << val << " ";

}

}

Any type which has non-member begin(type) and end(type) functions which can found via argument

dependent lookup, based on type. This is useful for creating a range type without having to modify class type itself:

namespace Mine

{

struct Rng {float arr[3];};

// pointers are iterators

const float* begin(const Rng &rng) {return &rng.arr[0];} const float* end(const Rng &rng) {return &rng.arr[3];} float* begin(Rng &rng) {return &rng.arr[0];}

float* end(Rng &rng) {return &rng.arr[3];}

}

int main()

{

Mine::Rng rng = {{0.4f, 12.5f, 16.234f}};

for(auto val: rng)

{

std::cout << val << " ";

}

}

Section 11.2: For loop

A for loop executes statements in the loop body, while the loop condition is true. Before the loop initialization

statement is executed exactly once. After each cycle, the iteration execution part is executed.

A for loop is defined as follows:

for (/*initialization statement*/; /*condition*/; /*iteration execution*/)

GoalKicker.com – C++ Notes for Professionals

46

{

// body of the loop

}

Explanation of the placeholder statements:

initialization statement: This statement gets executed only once, at the beginning of the for loop. You can enter a declaration of multiple variables of one type, such as int i = 0, a = 2, b = 3. These variables are only valid in the scope of the loop. Variables defined before the loop with the same name are hidden during execution of the loop.

condition: This statement gets evaluated ahead of each loop body execution, and aborts the loop if it evaluates to false.

iteration execution: This statement gets executed after the loop body, ahead of the next condition evaluation, unless the for loop is aborted in the body (by break, goto, return or an exception being thrown). You can enter multiple statements in the iteration execution part, such as a++, b+=10, c=b+a.

The rough equivalent of a for loop, rewritten as a while loop is:

/*initialization*/ while (/*condition*/)

{

// body of the loop; using 'continue' will skip to increment part below

/*iteration execution*/

}

The most common case for using a for loop is to execute statements a specific number of times. For example, consider the following:

for(int i = 0; i < 10; i++) { std::cout << i << std::endl;

}

A valid loop is also:

for(int a = 0, b = 10, c = 20; (a+b+c < 100); c--, b++, a+=c) { std::cout << a << " " << b << " " << c << std::endl;

}

An example of hiding declared variables before a loop is:

int i = 99; //i = 99

for(int i = 0; i < 10; i++) { //we declare a new variable i

//some operations, the value of i ranges from 0 to 9 during loop execution

}

//after the loop is executed, we can access i with value of 99

But if you want to use the already declared variable and not hide it, then omit the declaration part:

int i = 99; //i = 99

for(i = 0; i < 10; i++) { //we are using already declared variable i

//some operations, the value of i ranges from 0 to 9 during loop execution

}

//after the loop is executed, we can access i with value of 10

Notes:

GoalKicker.com – C++ Notes for Professionals

47