In theory, this is called every time because the for loop:
for(initialization; condition; increment) body;
expands to a value
{ initialization; while(condition) { body; increment; } }
(pay attention to curly braces, since initialization is already in the inner area)
In practice, if the compiler understands that part of your condition is invariant over the entire duration of the cycle, and it has no side effects, it may be smart enough to move it. This is usually done with strlen and such things (that the compiler knows well) in loops where its argument is not written.
However, it should be noted that this last condition is not always trivial to prove; in general, it is easy if the container is local to the function and is never passed to external functions; if the container is not local (for example, it is passed by reference, even if it is const ), and the body of the loop contains calls for other functions, the compiler often must assume that such functions can change it, thereby blocking the rise in length of the calculation.
Performing this optimization manually is worth the effort if you know that part of your condition is priced “expensive” (and this condition is usually not, since it usually comes down to subtracting the pointer, which is almost certainly embedded).
Edit: as others have said, in general it is better to use iterators with containers, but for vector this is not so important, because random access to elements through operator[] guaranteed to be O (1); in fact, with vectors it is usually the sum of the pointer (vector base + index) and dereferencing with increasing pointer (previous element + 1) and dereferencing iterators. Since the destination address is the same, I don’t think that you can get something from iterators in terms of cache locality (and even if it is, if you do not go through arrays in complex loops, you should not even notice such kind of improvements )
Instead of lists and other containers, using iterators instead of random access can be very important, because using random access can mean a walk every time the list is used, and incrementing the iterator is just dereferencing the pointer.