ViX44 wrote:
Code:
{ const unsigned lim = 10u;
for(unsigned i = 1, j; i <= lim; ++i)
for(j = 1u; j <= lim; ++j)
//if (j == 3u) break; //would run this line full 10 times
if( j == 3u )
i = lim; //will only run this thrice
}
Brace wrapping to limit the scope of
lim to the pertinent area. I would normally throw that into the
for loop (see next bulletpoint) but here the compiler can take advantage of its
const attribute and optimize.
Moving
j into the first
for declaration prevents it from being generated and destroyed (
automatic storage class) each
i loop.
Unsigned because we are not interested in negative numbers.
Prefix operator can be faster.
Setting
i to the limit is effective here, but I would prefer a boolean flag if this were a general case, since it would fail on
lim = std::numeric_limits<int type>::max(), where it would roll over to 0 or std::numeric_limits<int type>::min() on the increment, making the mathematics undefined and liable to hurt someone. However, the true sin is the use of <
=. Any time you have a foo <= or >= bar in a foor loop, you risk having an
all foo is true situation. Sanitize your limit so it must be in the data type's range and that lim is not a useful value of your incrementer. If that cannot be done, for example you may want to run all uint8_t values from 0 to 255, you'll need something else to catch the end condition, such as incrementing a uint16_t and testing
& 0x100).
A few things:
1) Limiting the scope of variables is good. However, don't do it for performance reasons (your compiler can see that you aren't using it elsewhere).
2) The cost of creating/destroying an automatic variable without a constructor/destructor is zero.
3) Unsigned operations are the same speed as signed operations on every platform ever

4) ++i will compile to the same thing as i++ if you aren't actually making use of the return value.
I don't want to be the person that is always saying "just let your compiler do it, it is smarter than you", because I don't believe that is true (a significant part of my work now is hand compiling stuff that compilers do a sucky job of). But doing tiny tweaks that could be done automatically by a computer program is a waste of your time.
The example is a bit contrived, so this ends up looking fairly verbose for something that doesn't do much. But this is how I would approach it:
Code:
typedef bool(*ConditionFunc)(Position p);
typedef struct {
int i;
int j;
} *Position;
bool condition(Position p) {
return (p->j == 3);
}
Position find_position(ConditionFunc filter) {
Position search = new Position();
for (search->i = 0; search->i <= 10; search->i++) {
for (search->j = 0; search->j <= 10; search->j++) {
if (filter(search)) {
return search;
}
}
}
delete(search);
return NULL;
}
...
blah = find_position(condition);