I've found a lot of discussion about loop invariant values and whether to declare them outside the loop or not. That is not what I'm concerned about. I'm concerned about loop variant values and whether declaring them explicitly has any potential performance implications.
A coworker recently sent out a piece of code. Let's say T is a sequence of integers, be it list, vector, etc.
#include <time.h>
#include <algorithm>
template <typename T>
clock_t _check(T &cont, int cnt)
{
clock_t starttime = clock();
srand(27);
while (cnt--)
{
int cur = (rand() << 10) | rand();
cont.insert(std::find_if(cont.begin(), cont.end(), [cur](int i) { return i >= cur; }), cur);
}
return clock() - starttime;
}
When I saw this code I immediate thought that I would change while loop to
T::iterator it = std::find_if(cont.begin(), cont.end(), [&](int i)
{
return i >= cur;
});
cont.insert(it, cur);
So basically, I would capture cur by reference, split the line into two parts, and some minor formatting differences. I don't think there's any potential performance downsides as far as the reference is concerned, but let me know if I'm wrong. What about the iterator? I prefer this because I think it more clearly illustrates the process, but am I accidentally making another temporary or taking away optimization opportunities?
I know what you're all going to say, profile and don't optimize prematurely. I know, I believe. The problem is that I come across the situation of declaring temporary variables in loops very frequently, and the variable may not be an iterator. What if it's a pointer, or some data structure that requires a deep copy? What if the function call gets this variable by reference to const versus value? It would be nice to have some insight on the theoretical implications so I can do it "the right way" immediately and not have to test all the time.
So, is there any downside to explicitly declaring temporary variables before they are used? Or does the compiler make these two completely equivalent? Maybe people like the fact that the first example is one line and mine is five?
EDIT: I forgot to explain why I thought of this. "C++ Coding Standards, 101 Rules, Guidelines, and Best Practices" by Sutter and Alexandrescu says in Item 9 that "It is not a premature optimization to reduce spurious temporary copies of objects, especially in inner loops, when doing so doesn't impact code complexity". Is this what they're talking about?
In very general terms, for a "good enough" compiler, you can always introduce a named local variable that substitutes for a compiler temporary with no impact on performance.
If you can satisfy yourself that by introducing a named local variable you are merely spelling out what the compiler was going to do anyway, then the compiler will (should) generate exactly the same code.
Obviously there are provisos on that. The named local variable should have the same lifetime, so that it can be kept in a register and not be forced into flushing to a memory location. There are situations where the compiler is permitted to delete (or inline) certain operations, and your substitution should not prevent it doing so.
In this particular case I believe the iterator will just be a pointer into the collection, so it should meet those provisos. There could be other cases where this is not so.
At this point I should make a plea for brevity. Some programmers prefer prolixity in the belief that more code makes it easier to read. I do not share that view. Your code should be as short as it possibly can be (but no shorter) and on those grounds the original is far better than your proposed changes, and also avoids the risk of confusing the compiler into generating worse code.