Prefer iterators over indices/keys.
While for vector
or array
there should be no difference between either form1, it is a good habit to get into for other containers.
1 As long as you use []
instead of .at()
for accesssing by index, of course.
Memorize the end-bound.
Recomputing the end-bound at each iteration is inefficient for two reasons:
- In general: a local variable is not aliased, which is more optimizer-friendly.
- On containers other than vector: computing the end/size could be a bit more expensive.
You can do so as a one-liner:
for (auto it = vec.begin(), end = vec.end(); it != end; ++it) { ... }
(This is an exception to the general prohibition on declaring a single variable at a time.)
Use the for-each loop form.
The for-each loop form will automatically:
- Use iterators.
- Memorize the end-bound.
Thus:
for (/*...*/ value : vec) { ... }
Take built-in types by values, other types by reference.
There is a non-obvious trade-off between taking an element by value and taking an element by reference:
- Taking an element by reference avoids a copy, which can be an expensive operation.
- Taking an element by value is more optimizer-friendly1.
At the extremes, the choice should be obvious:
- Built-in types (
int
, std::int64_t
, void*
, ...) should be taken by value.
- Potentially allocating types (
std::string
, ...) should be taken by reference.
In the middle, or when faced with generic code, I would recommend starting with references: it's better to avoid a performance cliff than attempting to squeeze out the last cycle.
Thus, the general form is:
for (auto& element : vec) { ... }
And if you are dealing with a built-in:
for (int element : vec) { ... }
1 This is a general principle of optimization, actually: local variables are friendlier than pointers/references because the optimizer knows all the potential aliases (or absence, thereof) of the local variable.