Jump to content
  • Advertisement
Sign in to follow this  
thecoast47

iterator variable type

This topic is 2479 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

My friend says im an idiot for using a variable of type unsigned int to iterate through std::vectors.
example:
for(unsigned int K =0; K < Vector.size();K++){
...
...
...
}
Is he right?
And if he is, why is he right?

Share this post


Link to post
Share on other sites
Advertisement
I'd be leery of anyone willing to blatantly insult you over a programming style choice.

Iterators can be nice, and they are good abstractions to use if you're likely to change containers (e.g. you can't iterate a std::list or std::map using unsigned indices), but they are not magic or super sauce that fixes cancer.

Your code is fine.

Share this post


Link to post
Share on other sites
performance issue perhaps?
because it has to check the container size every time it iterates.

If the size of your vector stays the same i would do something like:

const unsigned int kCount = Vector.size();

for(unsigned int K =0; K < kCount[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

; K++){[/font]



[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

...[/font]



[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

...[/font]



[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

...[/font]



[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

}[/font]



[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

You should ask your friend instead why does he thinks that it is a bad practice.[/font]

Share this post


Link to post
Share on other sites
Unless you're doing something truly pathological and/or using a really brain-dead compiler, that won't make much of a difference, really. It might help if the loop body is short and the counter limit can be placed into a register by the compiler, but if it has to go back to the stack to fetch kCount you'll be hard pressed to see a significant gain between the two styles.

Just write code that seems reasonable and is easy to read. Worry about tiny little "optimizations" (which usually are a waste of time) if and only if you have strong evidence from a profiler that you need to change a particular implementation detail.

Share this post


Link to post
Share on other sites
Iterating like that is pretty common, though I like to blame the extremely tedious syntax for using an iterator. Of course since C++11 you can finally just use
auto iter = Vector.begin()

Seriously though, it depends on many more factors. If there is any chance that your vector might at some point be replaced with a list or other container that doesn't allow random access, you will hate yourself for every location where you iterate with an index. But if your function is for example supposed to return the index of a certain element, I'd say this code is clearer than subtracting iterators. If you want to be extremely pedantic, use Vector::size_type instead of unsigned int.

Share this post


Link to post
Share on other sites

performance issue perhaps?
because it has to check the container size every time it iterates.

Huh? Its inlined, and an optimizing compiler is more than smart enough not to bother recalculating the value in a loop in which you do not modify the size of the container. Optimizations like that are a waste of time unless a profiler is showing it as actually being an issue (never seen it happen). Also, use size_t, its both shorter to type than "unsigned int" and also clarifies the intended usage of the index variable.

As for the whole "iterators" vs "indexing" it depends. If you are likely to end up needing to change the container type then using iterators is a good idea. If you know that you shouldn't need to (i.e. you need a dynamic array type for interfacing with a C api) then there's no reason to care. Both will end up, usually, compiling down to roughly the same machine code.

Share this post


Link to post
Share on other sites
[quote name='Vlad86' timestamp='1330370719' post='4917106']performance issue perhaps? because it has to check the container size every time it iterates.
Huh? Its inlined, and an optimizing compiler is more than smart enough not to bother recalculating the value in a loop in which you do not modify the size of the container. Optimizations like that are a waste of time unless a profiler is showing it as actually being an issue (never seen it happen).[/quote]The compiler often isn't allowed to make that optimisation due to aliasing -- if you're writing to an unknown address in the loop body, the optimiser can't know whether you might be writing to the size value, so it has to re-fetch it every iteration.
Yeah, it's usually not such a big deal that it matters that it's sub-optimal... but it is sub-optimal.template<class T> void SumOfVector( const std::vector<T>& input, T* output )
{
for( size_t i=0; i!=input.size(); ++i )
*output += i;
}
...
vector<size_t> foo;//assuming below that the size member is public and named m_size (this is probably not the case for any compiler)
SumOfVector( foo, &foo.m_size );//this should probably crash. If it doesn't, your compiler is probably non-compliant.
My personal preference is to explicitly state what it is that you expected the optimiser to figure out for you:
[font=courier new,courier,monospace]for( uint i=0, end=input.size(); i!=end; ++i )[/font]
or
[font=courier new,courier,monospace]for( iterator i=input.begin(), end=input.end(); i!=end; ++i )[/font]

but now we're bikeshedding laugh.png

Share this post


Link to post
Share on other sites

The compiler often isn't allowed to make that optimisation due to aliasing -- if you're writing to an unknown address in the loop body, the optimiser can't know whether you might be writing to the size value, so it has to re-fetch it every iteration.

Well, considering that most popular implementations of vector (i.e. microsoft's and GCC's) don't store a "size" variable, but instead use a pointer difference. Even then, it only needs to actually load a single variable into a register, and can usually cache that value in the register for the remainder of the loop, which means the subtraction only requires a fetch from one memory location. Even THEN, that will execute frequently enough it will be in a cache line.

Yeah, it's usually not such a big deal that it matters that it's sub-optimal... but it is sub-optimal.template<class T> void SumOfVector( const std::vector<T>& input, T* output )
{
for( size_t i=0; i!=input.size(); ++i )
*output += i;
}
...
vector<size_t> foo;//assuming below that the size member is public and named m_size (this is probably not the case for any compiler)
SumOfVector( foo, &foo.m_size );//this should probably crash. If it doesn't, your compiler is probably non-compliant.
[/quote]
If that even compiled on ANY platform at all. Most likely it won't compile on the vast majority of platforms and hence could never crash in the first place smile.png
My personal preference is to explicitly state what it is that you expected the optimiser to figure out for you:
[font=courier new,courier,monospace]for( uint i=0, end=input.size(); i!=end; ++i )[/font]
or
[font=courier new,courier,monospace]for( iterator i=input.begin(), end=input.end(); i!=end; ++i )[/font]

but now we're bikeshedding laugh.png
[/quote]
My personal preference is to write readable clean C++ code with the minimum number of excess just for the optimizer. However, that's also a bug prone method there, if your loop body DOES eventually end up modifying the size of the vector, you'll now be iterating over the wrong size. I worry about things like that when the profiler actually shows it to be an issue, which it almost never is. You're more likely to get a vastly superior speedup through algorithmic optimizations than by inlining the "size()" calls on your vectors. Especially since said size() calls are pretty much nearly free, what with the fact that the very pointers used in the subtraction are guaranteed to be in the cache (since you'll need them to fetch the next value ANYWAYS).

Besides which, this is For Beginners, not General Programming. KISS.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!