On https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html it is recommended to write for loops like the following:
Container::iterator end = large
The C++11 standard (§ 23.2.1) mandates that end
has O(1) complexity, so a conforming implementation would have the same performance characteristics for both versions.
That said, unless the compiler can prove that the return value of end
will never change then pulling end
out of the loop might be faster by some constant quantity (as Steve Jessop comments, there are lots of variables that can influence whether this is true or not).
Still, even if in one particular case there is absolutely no performance difference, pulling such tests out of the loop is a good habit to get into. An even better habit to get into is to utilize standard algorithms as @pmr says, which sidesteps the issue entirely.
In fact, the end() method is inline. The 2nd not call it every time, I don't think end() gives any performance lag.
Depends on the implementation, but I don't think end()
gives that much of a performance lag.
std::vector.end() (for example) return an iterator by value. In the second loop you create an object at every loop. The coding standard is telling you to do not create object if you don't need to. The compiler may be smart and optimize the code for you, however this is not guarantee. A much better solution is using stl algorithms. They are already optimized and your code will be more readable. Beware the two loops are equivalent only if you do not modified the collection.
P.S. it is very likely that the difference in performance is very minimal
For anyone reading this now, the question has become somewhat of a moot point with C++11.
I wasn't sure whether this response qualifies as an answer, because it doesn't actually address the point of the question. But I do think it's valid to point out that the problem raised here will be seldom encountered in practice for a C++11 programmer, and I certainly would have found this response useful a few years ago. This response is therefore aimed at the reader who simply wants to know the best way of iterating through all elements in a STL container (vector
, list
, deque
, etc.).
Assuming that the OP wanted access to each element in the container, we can easily sidestep the entire question of whether defining end
is sufficiently faster than calling Container::end()
by writing a range-based for loop:
Container container; // my STL container that has been filled with stuff
// (note that you can replace Container::value_type with the value in the container)
// the standard way
for (Container::value_type element : container) {
// access each element by 'element' rather than by '*it'
}
// or, if Container::value_type is large
Container container; // fill it with something
for (Container::value_type& element : container) {
//
}
// if you're lazy
Container container; // fill it with something
for (auto element : container) {
//
}
The OP has asked whether the trade-off between brevity of simply comparing it
to Container::end()
at every iteration and the performance of declaring a variable end
and comparing that at each step instead is worth it. Since range-based for loops provide a simple, easy to write and easy to read alternative that also happens to, internally, declare an end
iterator rather than calling the Container::end()
method at every step, the number of cases where we need to dwell on this question has been reduced to a limited number of cases.
As per cppreference.com, the range-based for loop will produce code with the same side-effects as the following:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
This is less about end
being costly and more about the ability of a compiler to see that end
will not change through a side effect in the loop body (that it is a loop invariant).
The complexity of end
is required to be constant by the standard. See table 96 in N3337 in 23.2.1
.
Using standard library algorithms circumvents the whole dilemma nicely.