why is this for loop taking so long? - c++

the for loop:
//for testing, this is usually a value of about 27
int test = level.PathLookupVectors()[globalNodePositionIndex][globalNodeChoice].size();
for (int i = 0; i < level.PathLookupVectors()[globalNodePositionIndex][globalNodeChoice].size(); i++)
{
//adds the correct nodes to the search
search.push_back(level.Nodes()[level.PathLookupVectors()[globalNodePositionIndex][globalNodeChoice][i]].Index());
}
and it's a 64 bit system.
I'm getting very strange results for the integer 'i' when debugging. it should be initialized to 0 but for some reason it's a very very high number which in turn means that the for loop is not executing.

EDIT - just changed it so that it's just an int, now it gets a value
of -82938723047 or some such number. why on earth is this happening?
It's ruining my program!
You are almost certainly barking up the wrong tree. The code:
for (int i = 0;
...initializes i to 0, period. If you're trying to spy its value in the debugger and the debugger says i has a value that looks like uninitialized, garbage data, then you are probably looking at i either before or after i has entered scope and been initialized. For example, in MSVC if you examine i before you enter the loop for the very first time, it will often have garbage data.
These are not the droids you're looking for. Move along.
Much more likely is this code:
level.PathLookupVectors()[globalNodePositionIndex][globalNodeChoice].size()
This is probably not doing what you think it's doing.
By the way, if the type of level.PathLookupVectors()[globalNodePositionIndex][globalNodeChoice] is a vector of some kind, I'd prefer that you use a for loop constructed like this.
/*psudocode*/ for( vector::iterator it = v.begin(), it_end = v.end(); it != it_end; ++it )
If you don't need the index of the element you're trying to access, then why refer to it? You're just introducing another potential failure point in your code.

Related

C++: Is it safe to change value of iterator of a while loop?

#include <iostream>
using namespace std;
int main() {
int x = 10;
while (x>0) {
x = x-1;
cout << x << "\n";
}
return 0;
}
In this simple program, I change value of iterator of a while loop. But is it safe to do that? Will the program run into segmentation fault sometimes?
How about this pseudo code:
vector <vector<Struct> > all_vectors;
vector<Struct> old_vector, new_vector;
Initialize old_vector;
all_vectors.push_back(old_vector);
index = 0;
while (all_vectors[index].size()>0) {
calculate new_vector;
if (new_vector not empty) all_vectors.push_back(new_vector);
index += 1;
}
My real code is a bit messy and lengthy so I only posted the main idea of my real code. But for this case, I run into segmentation fault. When I try to debug, the problem seems to be with the line: index += 1.
I cannot understand why. I am sorry if my code is not readable, I am just learning C++.
I'm guessing now, but if your loop look something like the second example you provide, the segmentation fault could be caused by the check in the while statement.
...
index = 0;
while (all_vectors[index].size() > 0) {
^-- This, this could be the problem
...
index += 1;
}
The reason being that the program tries to access a vector that is out of range.
This would probably fix the problem
...
while (index < all_vectors.size() && all_vectors[index].size() > 0) {
^---- Check this index first ^---- only checked if first condition is true
...
And by the look of it, i would recommend using a for loop instead:
...
for (size_t index = 0; index < all_vectors.size() && all_vectors[index].size() > 0; ++i) {
...
I could also recommend when having segmentation fault with vectors to use .at() instead of operator[] because that does a range check, and can help you find the problem faster.
You want to ask whether changing the value of the loop variable (x) is safe or not. Remember, an iterator is an object (like a pointer) that points to an element inside the container so the integer variable int x is not an iterator.
Now, the answer to your question would be that it is totally safe to change the value of the loop variable inside the loop body. You cannot expect the loop to terminate if you are not changing the value of the loop variable!
Coming to the second part, changing the value illogically would result to an infinite loop or a segmentation fault. Suppose, you have written x=x+1 instead of x=x-1 inside the loop body, the value of x will always be more than 0 in this case and hence the loop will never terminate.
It is inherently necessary to change the value of an input iterator in order to advance (in typical cases). If you don't change the iterator that is used as the end condition, then you will never reach the end of the interations unless the iteration starts at the end - i.e. there are zero iterations.
Note that iterator is different concept from a loop variable, but the answer applies equally to loop variables as well.

Using < or != in for loop termination condition

Given a vector v, I want to loop through each element in the vector and perform an operation that requires the current index.
I've seen a basic for loop written both of these ways:
// Using "<" in the terminating condition
for (auto i = 0; i < v.size(); ++i)
{
// Do something with v[i]
}
// Using "!=" in the terminating condition
for (auto i = 0; i != v.size(); ++i)
{
// Do something with v[i]
}
Is there any practical reason to prefer one over the other? I've seen it written using < much more often, but is there a performance benefit to using !=?
There is one, albeit kinda convoluted, reason to prefer < over !=.
If for whatever reason the body of your lop modifies i and skips over the threshold, < still terminates the loop, where != will keep iterating.
It might make no difference in the vast majority of cases, but getting used to < might prevent bugs that != won't. There's also an additional advantage, that is ridiculously minor but < takes less characters to write, so it makes the source file smaller.
Again the above argument is borderline a joke, but if you need an argument to use one over the other, there you have it.
You should probably prefer using a range-for instead.
Is there any practical reason to prefer one over the other?
There are no strong reasons to prefer one way or another given that both have equivalent behaviour.
Using the less than operator works even if the end condition is not one of the values of the accumulator which would be possible if increment was greater than 1 or the initial value was greater than the end condition. As such, it is more general, which means that using it always may be more consistent. Consistency is a weak argument, but a weak argument is better than no argument if you agree with it.
There is no difference in performance.
There is a huge difference if you decided to change ++i in such a way that the loop would step over the desired end.
For clarity for other programmers reading your code, use the convention they expect to see, namely <. When I see i != ..., I think "he is skipping over that one value".
The is an obscure bug with < -- Suppose you iterating over all 256 chars using a byte-sized i. The value will overflow and probably never show the value 256. The loop will never stop. And != won't fix the bug.

Heap Buffer Overflow occurs randomly....... for a simple code?(I'm new to C++)

ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000114 at pc 0x000000406d27 bp 0x7ffc88f07560 sp 0x7ffc88f07558
READ of size 4 at 0x602000000114 thread T0
LeetCode No.1
I get this when I give this code
The code below works for some other inputs, but for [3,2,4]\n6, it shows the above error.
vector<int> twoSum(vector<int>& nums, int target) {
int first = 0,last = nums.size() - 1;
vector<int> ref = nums;
while(first < last){
if(ref[first]+ref[last] > target) last--;
else if(ref[first]+ref[last] < target) first++;
else break;
}
vector<int> result;
for(int i=0;i<nums.size();i++){
if(ref[first]==nums[i]) result.push_back(i);
else if(ref[last]==nums[i]) result.push_back(i);
}
if(result[0] > result[1])
swap(result[0],result[1]);
return result;
}
The expected output is [1,2], indexes of values in the array adding up to the value 6.
Consider this while loop.
while(first < last){
if(ref[first]+ref[last] > target) last--;
else if(ref[first]+ref[last] < target) first++;
else break;
}
It seems that the intent was to break and exit when the sum is exactly equal to the target number. However, it is not guaranteed that this will become true. You can also exit the loop when the while condition fails, which happens whenever you reach first == last without yet finding any exact match. That actually happens in the particular case you mention. Follow the logic through and you will find this yourself. The search process misses the desired answer. The logic will not find [1,2]. It will first consider [0,2] and when that fails as too big, it will permanently decrement last and never again consider any combination that involves position 2.
(Likewise, if it fails for being too small it would increment the first position and never again consider combinations with the first value. So there are other failure cases that would happen similarly with that scenario.)
Since you exit without finding the matching combination and first == last, only one number will be pushed into the results. Therefore, when you just assume there are two numbers (false), things blow up as you try to reference the second result number.
General Observation:
You need to plan for the case where no exact match is found and code with that possibility in mind. In that case, what would a correct return result look like to signify no solution was found?
Plus, you could think about how the algorithm could be better at not missing a solution when it is actually present. However, that doesn't change the first requirement. If the target cannot be matched by any sum, you need to be ready for that possibility.
Side Notes:
Rather than repeat the sum of two in if statements, when the sum isn't changing I would suggest that you could create and use an auto local variable once that is
auto sum(ref[first]+ref[last]);
If you want to ensure that argument vector nums is not changed, and communicate that clearly to anyone looking at the declaration of the function, a better choice would be the pass it as a const reference, e.g.
(const vector<int>& nums, ...)
Why does the code create a local copy called ref of the argument vector nums? What is the point of making the effort to make the copy?
Regarding...
last = nums.size() - 1
...notice that if the vector passed in is empty, the value of last goes negative. That might not cause a problem for some code, but it has a dangerous smell in that it looks like code that is just assuming that the vector passed in would never be empty. Practice defensive coding that can be seen to guard against the possibility of unusual input values.
p.s. Part of what saves that last initialization from being broken is the use of int. Since size() returns size_t (unsigned), a common problem is to handle it as unsigned size_t. Then instead of going negative, the result wraps around to the maximum value and the looping may try to work with that as if that was a valid position in the vector. It's hazardous to get into habits that invite those kinds of bugs.

Is there a technical reason to use > (<) instead of != when incrementing by 1 in a 'for' loop?

I almost never see a for loop like this:
for (int i = 0; 5 != i; ++i)
{}
Is there a technical reason to use > or < instead of != when incrementing by 1 in a for loop? Or this is more of a convention?
while (time != 6:30pm) {
Work();
}
It is 6:31pm... Damn, now my next chance to go home is tomorrow! :)
This to show that the stronger restriction mitigates risks and is probably more intuitive to understand.
There is no technical reason. But there is mitigation of risk, maintainability and better understanding of code.
< or > are stronger restrictions than != and fulfill the exact same purpose in most cases (I'd even say in all practical cases).
There is duplicate question here; and one interesting answer.
Yes there is a reason. If you write a (plain old index based) for loop like this
for (int i = a; i < b; ++i){}
then it works as expected for any values of a and b (ie zero iterations when a > b instead of infinite if you had used i == b;).
On the other hand, for iterators you'd write
for (auto it = begin; it != end; ++it)
because any iterator should implement an operator!=, but not for every iterator it is possible to provide an operator<.
Also range-based for loops
for (auto e : v)
are not just fancy sugar, but they measurably reduce the chances to write wrong code.
You can have something like
for(int i = 0; i<5; ++i){
...
if(...) i++;
...
}
If your loop variable is written by the inner code, the i!=5 might not break that loop. This is safer to check for inequality.
Edit about readability.
The inequality form is way more frequently used. Therefore, this is very fast to read as there is nothing special to understand (brain load is reduced because the task is common). So it's cool for the readers to make use of these habits.
And last but not least, this is called defensive programming, meaning to always take the strongest case to avoid current and future errors influencing the program.
The only case where defensive programming is not needed is where states have been proven by pre- and post-conditions (but then, proving this is the most defensive of all programming).
I would argue that an expression like
for ( int i = 0 ; i < 100 ; ++i )
{
...
}
is more expressive of intent than is
for ( int i = 0 ; i != 100 ; ++i )
{
...
}
The former clearly calls out that the condition is a test for an exclusive upper bound on a range; the latter is a binary test of an exit condition. And if the body of the loop is non-trivial, it may not apparent that the index is only modified in the for statement itself.
Iterators are an important case when you most often use the != notation:
for(auto it = vector.begin(); it != vector.end(); ++it) {
// do stuff
}
Granted: in practice I would write the same relying on a range-for:
for(auto & item : vector) {
// do stuff
}
but the point remains: one normally compares iterators using == or !=.
The loop condition is an enforced loop invariant.
Suppose you don't look at the body of the loop:
for (int i = 0; i != 5; ++i)
{
// ?
}
in this case, you know at the start of the loop iteration that i does not equal 5.
for (int i = 0; i < 5; ++i)
{
// ?
}
in this case, you know at the start of the loop iteration that i is less than 5.
The second is much, much more information than the first, no? Now, the programmer intent is (almost certainly) the same, but if you are looking for bugs, having confidence from reading a line of code is a good thing. And the second enforces that invariant, which means some bugs that would bite you in the first case just cannot happen (or don't cause memory corruption, say) in the second case.
You know more about the state of the program, from reading less code, with < than with !=. And on modern CPUs, they take the same amount of time as no difference.
If your i was not manipulated in the loop body, and it was always increased by 1, and it started less than 5, there would be no difference. But in order to know if it was manipulated, you'd have to confirm each of these facts.
Some of these facts are relatively easy, but you can get wrong. Checking the entire body of the loop is, however, a pain.
In C++ you can write an indexes type such that:
for( const int i : indexes(0, 5) )
{
// ?
}
does the same thing as either of the two above for loops, even down to the compiler optimizing it down to the same code. Here, however, you know that i cannot be manipulated in the body of the loop, as it is declared const, without the code corrupting memory.
The more information you can get out of a line of code without having to understand the context, the easier it is to track down what is going wrong. < in the case of integer loops gives you more information about the state of the code at that line than != does.
As already said by Ian Newson, you can't reliably loop over a floating variable and exit with !=. For instance,
for (double x=0; x!=1; x+=0.1) {}
will actually loop forever, because 0.1 can't exactly be represented in floating point, hence the counter narrowly misses 1. With < it terminates.
(Note however that it's basically undefined behaviour whether you get 0.9999... as the last accepted number – which kind of violates the less-than assumption – or already exit at 1.0000000000000001.)
Yes; OpenMP doesn't parallelize loops with the != condition.
It may happen that the variable i is set to some large value and if you just use the != operator you will end up in an endless loop.
As you can see from the other numerous answers, there are reasons to use < instead of != which will help in edge cases, initial conditions, unintended loop counter modification, etc...
Honestly though, I don't think you can stress the importance of convention enough. For this example it will be easy enough for other programmers to see what you are trying to do, but it will cause a double-take. One of the jobs while programming is making it as readable and familiar to everyone as possible, so inevitably when someone has to update/change your code, it doesn't take a lot of effort to figure out what you were doing in different code blocks. If I saw someone use !=, I'd assume there was a reason they used it instead of < and if it was a large loop I'd look through the whole thing trying to figure out what you did that made that necessary... and that's wasted time.
I take the adjectival "technical" to mean language behavior/quirks and compiler side effects such as performance of generated code.
To this end, the answer is: no(*). The (*) is "please consult your processor manual". If you are working with some edge-case RISC or FPGA system, you may need to check what instructions are generated and what they cost. But if you're using pretty much any conventional modern architecture, then there is no significant processor level difference in cost between lt, eq, ne and gt.
If you are using an edge case you could find that != requires three operations (cmp, not, beq) vs two (cmp, blt xtr myo). Again, RTM in that case.
For the most part, the reasons are defensive/hardening, especially when working with pointers or complex loops. Consider
// highly contrived example
size_t count_chars(char c, const char* str, size_t len) {
size_t count = 0;
bool quoted = false;
const char* p = str;
while (p != str + len) {
if (*p == '"') {
quote = !quote;
++p;
}
if (*(p++) == c && !quoted)
++count;
}
return count;
}
A less contrived example would be where you are using return values to perform increments, accepting data from a user:
#include <iostream>
int main() {
size_t len = 5, step;
for (size_t i = 0; i != len; ) {
std::cout << "i = " << i << ", step? " << std::flush;
std::cin >> step;
i += step; // here for emphasis, it could go in the for(;;)
}
}
Try this and input the values 1, 2, 10, 999.
You could prevent this:
#include <iostream>
int main() {
size_t len = 5, step;
for (size_t i = 0; i != len; ) {
std::cout << "i = " << i << ", step? " << std::flush;
std::cin >> step;
if (step + i > len)
std::cout << "too much.\n";
else
i += step;
}
}
But what you probably wanted was
#include <iostream>
int main() {
size_t len = 5, step;
for (size_t i = 0; i < len; ) {
std::cout << "i = " << i << ", step? " << std::flush;
std::cin >> step;
i += step;
}
}
There is also something of a convention bias towards <, because ordering in standard containers often relies on operator<, for instance hashing in several STL containers determines equality by saying
if (lhs < rhs) // T.operator <
lessthan
else if (rhs < lhs) // T.operator < again
greaterthan
else
equal
If lhs and rhs are a user defined class writing this code as
if (lhs < rhs) // requires T.operator<
lessthan
else if (lhs > rhs) // requires T.operator>
greaterthan
else
equal
The implementor has to provide two comparison functions. So < has become the favored operator.
There are several ways to write any kind of code (usually), there just happens to be two ways in this case (three if you count <= and >=).
In this case, people prefer > and < to make sure that even if something unexpected happens in the loop (like a bug), it won't loop infinitely (BAD). Consider the following code, for example.
for (int i = 1; i != 3; i++) {
//More Code
i = 5; //OOPS! MISTAKE!
//More Code
}
If we used (i < 3), we would be safe from an infinite loop because it placed a bigger restriction.
Its really your choice whether you want a mistake in your program to shut the whole thing down or keep functioning with the bug there.
Hope this helped!
The most common reason to use < is convention. More programmers think of loops like this as "while the index is in range" rather than "until the index reaches the end." There's value is sticking to convention when you can.
On the other hand, many answers here are claiming that using the < form helps avoid bugs. I'd argue that in many cases this just helps hide bugs. If the loop index is supposed to reach the end value, and, instead, it actually goes beyond it, then there's something happening you didn't expect which may cause a malfunction (or be a side effect of another bug). The < will likely delay discovery of the bug. The != is more likely to lead to a stall, hang, or even a crash, which will help you spot the bug sooner. The sooner a bug is found, the cheaper it is to fix.
Note that this convention is peculiar to array and vector indexing. When traversing nearly any other type of data structure, you'd use an iterator (or pointer) and check directly for an end value. In those cases you have to be sure the iterator will reach and not overshoot the actual end value.
For example, if you're stepping through a plain C string, it's generally more common to write:
for (char *p = foo; *p != '\0'; ++p) {
// do something with *p
}
than
int length = strlen(foo);
for (int i = 0; i < length; ++i) {
// do something with foo[i]
}
For one thing, if the string is very long, the second form will be slower because the strlen is another pass through the string.
With a C++ std::string, you'd use a range-based for loop, a standard algorithm, or iterators, even if though the length is readily available. If you're using iterators, the convention is to use != rather than <, as in:
for (auto it = foo.begin(); it != foo.end(); ++it) { ... }
Similarly, iterating a tree or a list or a deque usually involves watching for a null pointer or other sentinel rather than checking if an index remains within a range.
One reason not to use this construct is floating point numbers. != is a very dangerous comparison to use with floats as it'll rarely evaluate to true even if the numbers look the same. < or > removes this risk.
There are two related reasons for following this practice that both have to do with the fact that a programming language is, after all, a language that will be read by humans (among others).
(1) A bit of redundancy. In natural language we usually provide more information than is strictly necessary, much like an error correcting code. Here the extra information is that the loop variable i (see how I used redundancy here? If you didn't know what 'loop variable' means, or if you forgot the name of the variable, after reading "loop variable i" you have the full information) is less than 5 during the loop, not just different from 5. Redundancy enhances readability.
(2) Convention. Languages have specific standard ways of expressing certain situations. If you don't follow the established way of saying something, you will still be understood, but the effort for the recipient of your message is greater because certain optimisations won't work. Example:
Don't talk around the hot mash. Just illuminate the difficulty!
The first sentence is a literal translation of a German idiom. The second is a common English idiom with the main words replaced by synonyms. The result is comprehensible but takes a lot longer to understand than this:
Don't beat around the bush. Just explain the problem!
This is true even in case the synonyms used in the first version happen to fit the situation better than the conventional words in the English idiom. Similar forces are in effect when programmers read code. This is also why 5 != i and 5 > i are weird ways of putting it unless you are working in an environment in which it is standard to swap the more normal i != 5 and i < 5 in this way. Such dialect communities do exist, probably because consistency makes it easier to remember to write 5 == i instead of the natural but error prone i == 5.
Using relational comparisons in such cases is more of a popular habit than anything else. It gained its popularity back in the times when such conceptual considerations as iterator categories and their comparability were not considered high priority.
I'd say that one should prefer to use equality comparisons instead of relational comparisons whenever possible, since equality comparisons impose less requirements on the values being compared. Being EqualityComparable is a lesser requirement than being LessThanComparable.
Another example that demonstrates the wider applicability of equality comparison in such contexts is the popular conundrum with implementing unsigned iteration down to 0. It can be done as
for (unsigned i = 42; i != -1; --i)
...
Note that the above is equally applicable to both signed and unsigned iteration, while the relational version breaks down with unsigned types.
Besides the examples, where the loop variable will (unintentional) change inside the body, there are other reasions to use the smaller-than or greater-than operators:
Negations make code harder to understand
< or > is only one char, but != two
In addition to the various people who have mentioned that it mitigates risk, it also reduces the number of function overloads necessary to interact with various standard library components. As an example, if you want your type to be storable in a std::set, or used as a key for std::map, or used with some of the searching and sorting algorithms, the standard library usually uses std::less to compare objects as most algorithms only need a strict weak ordering. Thus it becomes a good habit to use the < comparisons instead of != comparisons (where it makes sense, of course).
There is no problem from a syntax perspective, but the logic behind that expression 5!=i is not sound.
In my opinion, using != to set the bounds of a for loop is not logically sound because a for loop either increments or decrements the iteration index, so setting the loop to iterate until the iteration index becomes out of bounds (!= to something) is not a proper implementation.
It will work, but it is prone to misbehavior since the boundary data handling is lost when using != for an incremental problem (meaning that you know from the start if it increments or decrements), that's why instead of != the <>>==> are used.

c++ for loop temporary variable use

Which of the following is better and why? (Particular to c++)
a.
int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
//loop body
}
b.
for( int i(0);i < vec.length(); ++i)
{
//loop body
}
I have seen advice for (a) because of the call to length function. This is bothering me. Doesn't any modern compiler do the optimization of (b) to be similar to (a)?
Example (b) has a different meaning to example (a), and the compiler must interpret it as you write it.
If, (for some made-up reason that I can't think of), I wrote code to do this:
for( int i(0);i < vec.length(); ++i)
{
if(i%4 == 0)
vec.push_back(Widget());
}
I really would not have wanted the compiler to optimise out each call to vec.length(), because I would get different results.
I like:
for (int i = 0, e = vec.length(); i != e; ++i)
Of course, this would also work for iterators:
for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)
I like this because it's both efficient (calling end() just once), and also relatively succinct (only having to type vector<int>::const_iterator once).
I'm surprised nobody has said the obvious:
In 99.99% of cases, it doesn't matter.
Unless you are using some container where calculating size() is an expensive operation, it is unfathomable that your program will go even a few nanoseconds slower. I would say stick with the more readable until you profile your code and find that size() is a bottleneck.
There are two issues to debate here:
The variable scope
The end condition re-evaluation
Variable scope
Normally, you wouldn't need the loop variable to be visible outside of the loop. That's why you can declare it inside the for construct.
End condition re-evaluation
Andrew Shepherd stated it nicely: it means something different to put a function call inside the end condition:
for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
if( ... ) v.push_back( i ); // contrived, but possible
}
// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}
Why is it bodering you?
Those two alternatives dont see to be doing the same. One is doing a fixed number of iterations, while the other is dependant on the loops body.
Another alternative colud be
for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
//loop body
}
Unless you need the loop variable outside the loop, the second approach is preferable.
Iterators will actually give you as good or better performance. (There was a big comparison thread on comp.lang.c++.moderated a few years back).
Also, I would use
int i = 0;
Rather than the constructor like syntax you're using. While valid, it's not idiomatic.
Somewhat unrelated:
Warning: Comparison between signed and unsigned integer.
The correct type for array and vector indices is size_t.
Strictly speaking, in C++ it is even std::vector<>::size_type.
Amazing how many C/C++ developers still get this one wrong.
Let's see on the generated code (I use MSVS 2008 with full optimization).
a.
int i(0), iMax(vec.size());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
//loop body
}
The for loop produces 2 assembler instructions.
b.
for( int i(0);i < vec.size(); ++i)
{
//loop body
}
The for loop produces 8 assembler instructions. vec.size() is successfully inlined.
c.
for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
//loop body
}
The for loop produces 15 assembler instructions (everything is inlined, but the code has a lot of jumps)
So, if your application is performance critical use a). Otherwise b) or c).
It should be noted that the iterator examples:
for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
//loop body
}
could invalidate the loop iterator 'it' should the loop body cause the vector to reallocate. Thus it is not equivalent to
for (int i=0;i<vec.size();++i){
//loop body
}
where loop body adds elements to vec.
Simple question: are you modifying vec in the loop?
answer to this question will lead to your answer too.
jrh
It's very hard for a compiler to hoist the vec.length() call in the safe knowledge that it's constant, unless it gets inlined (which hopefully it often will!). But at least i should definitely be declared in the second style "b", even if the length call needs to be "manually" hoisted out of the loop!
This one is preferable:
typedef vector<int> container; // not really required,
// you could just use vector<int> in for loop
for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
// do something with (*i)
}
I can tell right away that the vector
is not being updated
anyone can tell what is happening
here
I know how many loops
v.end() returns pointer one past the
last element so there's no overhead
of checking size
easy to update for different
containers or value types
(b) won't calculate/call the function each time.
-- begin excerpt ----
Loop Invariant Code Motion:
GCC includes loop invariant code motion as part of its loop optimizer as well as in its partial redundancy elimination pass. This optimization removes instructions from loops, which compute a value which does not change throughout the lifetime of a loop.
--- end excerpt --
More optimizations for gcc:
https://www.in.redhat.com/software/gnupro/technical/gnupro_gcc.php3
Why not sidestep the issue entirely with BOOST_FOREACH
#include <boost/foreach.hpp>
std::vector<double> vec;
//...
BOOST_FOREACH( double &d, vec)
{
std::cout << d;
}