Your case is one of them, there are others as well, like the difference between these two pieces of code: for (int i = 0 i < n ++i) But if you want to get a performance boost, it is best to write your code with some considerations. The key figure is that it is called each time. GCC was able to "see" here, that the body of the loop does not alter the size any way.Īs others said, The compiler shall decide what to do with the actual code written. Then, there was no evaluation of v.size() (subtraction of pointers) within the loop on an assembly level. Surprisingly, even when v.size() cannot change here, the generated assembly was the same as in the first case (with additional mov, sub, and sar instructions).Īdditionally, when I changed the loop into: for (size_t i = 0 i < v.size() i++) I even tried a different version where the vector is marked as being const: int g(const std::vector&, size_t) The value of the vector's size is simply kept in a register ( rbp). If we rewrite the code as follows: int g(std::vector&, size_t) įor (size_t i = 0, e = v.size() i >&, unsigned long) Sar rax, 2 // result * sizeof(int) => size() Sub rax, QWORD PTR // subtracts another poniter The requirement is that the resulting program must preserve observable effects of the code according to the rules of the C++ Standard. A C++ compiler translates some source code into a binary program. The problem with your question is that it does not make any sense. Since the target address is still the same, I don't think that you can gain something from iterators in terms of cache locality (and even if so, if you're not walking big arrays in tight loops you shouldn't even notice such kind of improvements).įor lists and other containers, instead, using iterators instead of random access can be really important, since using random access may mean walk every time the list, while incrementing an iterator is just a pointer dereference. it's passed by reference - even if it's const) and the loop body contains calls to other functions, the compiler often has to assume that such functions may alter it, thus blocking the hoisting of the length calculation.ĭoing that optimization by hand is worthy if you know that a part of your condition is "expensive" to evaluate (and such condition usually isn't, since it usually boils down to a pointer subtraction, which is almost surely inlined).Įdit: as others said, in general with containers it's better to use iterators, but for vectors it's not so important, because random access to elements via operator is guaranteed to be O(1) actually with vectors it usually is a pointer sum (vector base+index) and dereference vs the pointer increment (preceding element+1) and dereference of iterators. However it must be noted that this last condition isn't always trivial to prove in general, it's easy if the container is local to the function and is never passed to external functions if the container is not local (e.g. This is routinely done with strlen and things like that (that the compiler knows well) in loops where its argument isn't written. In practice, if the compiler understands that a piece of your condition is invariant through all the duration of the loop and it does not have side-effects, it can be smart enough to move it out. (notice the curly braces, because initialization is already in an inner scope) In theory, it is called each time, since a for loop: for(initialization condition increment)
0 Comments
Leave a Reply. |