1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
The bf(C++) for-statement is identical to bf(C)'s for-statement:
verb(
for (init; cond; inc)
statement
)
Often the initialization, condition, and increment parts are fairly
obvious, as in situations where all elements of an array or vector must be
processed. Many languages offer the tt(foreach) statement for that and bf(C++)
offers the tt(std::for_each) generic algorithm (cf. section ref(FOREACH)).
In addition to the traditional syntax bf(C++) adds new syntax for the
tt(for)-statement: the
emi(range-based for-loop). This new syntax can be used to process all
element of a i(range) in turn. Three types of ranges are distinguished:
itemization(
it() Plain arrays (e.g., tt(int array[10]));
it() Initializer lists;
it() Standard containers (or comparable) (cf. chapter
ref(CONTAINERS));
it() Any other type offering tt(begin()) and tt(end()) functions
returning so-called em(iterators) (cf. section ref(ITERATORS)).
)
Here the following additional i(for-statement) syntax is available:
verb(
// assume int array[30]
for (auto &element: array)
statement
)
The part to the left of the colon is called the
emi(for range declaration). The declared variable (tt(element)) is a
formal name; use any identifier you like. The variable is only
available within the nested statement, and it refers to (or is a copy of) each
of the elements of the range, from the first element up to the last.
There's no formal requirement to use tt(auto), but using tt(auto) is extremely
useful in many situations. Not only in situations where the range refers to
elements of some complex type, but also in situations where you know what you
can do with the elements in the range, but don't care about their exact type
names. In the above example tt(int) could also have been used.
The reference symbol (tt(&)) is important in the following cases:
itemization(
it() if you want to modify the elements in the nested statements
it() if the elements themselves are tt(struct)s (or em(classes),
cf. chapter ref(Classes))
)
When the reference symbol is omitted the variable will be a copy of each
of the subsequent elements of the range. Fine, probably, if you merely need to
look at the variables when they are of primitive types, but needlessly
inefficient if you have an array of tt(BigStruct) elements:
verb(
struct BigStruct
{
double array[100];
int last;
};
)
Inefficient, because you don't need to make copies of the array's
elements. Instead, use refences to elements:
verb(
BigStruct data[100]; // assume properly initialized elsewhere
int countUsed()
{
int sum = 0;
// const &: the elements aren't modified
for (auto const &element: data)
sum += element.last;
return sum;
}
)
If tt(data) is only available as a pointer to its first element in
combination with the number of elements, range-based for loops can also be
used, but require a little help. Section ref(RANGER) describes a generic
approach to using range based for loops in such cases.
|