-
September 18th, 2009, 10:35 PM
#1
Which practice of iteration through containers is preferred
In the "real world" what kind of loop do most people use to iterate through a container like a vector.
A loop like this...
Code:
for (int i = 0; i < v.size(); ++i) {
// do whatever
}
Or like this...
Code:
for (vector<T>::iterator i = v.begin(); i != v.end(); ++i) {
// do whatever
}
In addition to this question, I'm also wondering what's preferred in terms of output of a container. Iterating through its elements (like shown above) or using the copy algorithm with a stream iterator like this.
Code:
ostream_iterator<T> os(cout);
copy(v.begin(), v.end(), os);
Just some general coding practice questions for those in the industry. Any information is appreciated. Thanks.
-
September 18th, 2009, 10:40 PM
#2
Re: Which practice of iteration through containers is preferred
For vectors specifically, I usually use an integer index simply because it's quicker to type. That may change once the "auto" keyword is repurposed in C++0x.
Of course, any time the container type is templated and thus unknown, you have to use iterators.
-
September 19th, 2009, 04:47 AM
#3
Re: Which practice of iteration through containers is preferred
I always use iterators as if my life depended on it. It takes a bit more to write, and it takes a bit of time to learn to use, but the benefits are high.
Why? Static type safety and out of bounds protection.
example:
Code:
for ( int i = 0 ; i <= vect1.size() ; ++i)
{
for ( int j = 0 ; j <= vect2.size() ; ++j)
{
vect3.pushback(vect2[i]+vect1[j]);
}
}
In the above example, there are two problems. One: index out of bounds when i == size. Also, i describes indexes of vect1, but writing vect2[i] is completly legal!
Compare with this:
Code:
std::vector<int>::const_iterator it1 = vect1.begin();
const std::vector<int>::const_iterator it1end = vect1.end();
for ( ; it1 != it1end ; ++it1 )
{
std::vector<int>::const_iterator it2 = vect2.begin();
const std::vector<int>::const_iterator it2end = vect2.end();
for ( ; it2 != it2end ; ++it2 )
{
vect3.pushback(*it1 + *it2);
}
}
Now here, inside the loop, the objects *it1 and *it2 are perfectly defined. You never have to worry about i,j, or even k,m and n (for really embedded loops). You can't mess up. Also, while at first it might look like writing the loop is longer, it is also perfectly standardized to any container.
I have a blank loop "template" which I copy paste at my work, like this.
Code:
CNTNR::const_iterator it = OBJ.begin();
const CNTNR::const_iterator itEnd = OBJ.end();
for ( ; it != itEnd ; ++it )
{
}
Just replace CNTNR with your container type, and OBJ with your actual object. Notice you don't even have to touch the for part. it is always "stop at itEnd"
-
September 19th, 2009, 04:56 AM
#4
Re: Which practice of iteration through containers is preferred
Originally Posted by Lindley
For vectors specifically, I usually use an integer index simply because it's quicker to type. That may change once the "auto" keyword is repurposed in C++0x.
I think C++0x also includes a for each implementation which will be even quicker to type.
Rich
Visual Studio 2010 Professional | Windows 7 (x64)
Ubuntu
-
September 19th, 2009, 05:00 AM
#5
Re: Which practice of iteration through containers is preferred
Originally Posted by trikker
I'm also wondering what's preferred in terms of output of a container. Iterating through its elements (like shown above) or using the copy algorithm with a stream iterator like this.
The use of std::copy would be more descriptive. Of course, if you create another function specifically to output the elements, that would be be even more descriptive, with that function being implemented with std::copy.
-
September 19th, 2009, 05:07 AM
#6
Re: Which practice of iteration through containers is preferred
I normally use the "most advanced" method that will leave the code readable. That is, if I need to get the sum of the values in a vector e.g., I'll use std::accumulate. With more complex operations having a function object can obfuscate code, so then I'll likely use iterators, but sometimes also BOOST_FOR_EACH. The latter is especially nice when you have a container of pointers. Instead of writing
Code:
// typedef ... Iter
for (Iter it = my_container.begin(), end = my_container.end(); it != end; ++it) {
(*it)->DoSomething();
}
you can write
// typedef ... ValueType
BOOST_FOR_EACH (ValueType ptr, my_container) {
ptr->DoSomething();
}
[/code]
This can be a lot easier to read.
However, when I either need an index of an element or when I need to access elements from multiple vectors of the same size, I'll use a for loop with an index, because I find that is the best way to keep the code readable. Having more than one iterator in one or more nested loops is generally confusing, I find.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
September 21st, 2009, 06:12 PM
#7
Re: Which practice of iteration through containers is preferred
Originally Posted by trikker
In the "real world" what kind of loop do most people use to iterate through a container like a vector.
You should know that in the "real world" most things are done the wrong way. Instead you should aim at doing things the right way according to time-tested principles.
One such principle is to use the highest possible abstraction available. This means that you "scan" the container assuming as little as possible about the actual container.
-
September 22nd, 2009, 03:42 AM
#8
Re: Which practice of iteration through containers is preferred
Originally Posted by trikker
In the "real world" what kind of loop do most people use to iterate through a container like a vector.
It depends.
If I have a function that takes a pair of iterators then I may usually don't bother with a for loop and either use an STL algorithm or a simple while loop.
Code:
void Function(vector<int>::iterator begin, const vector<int>::iterator &end)
{
while (begin != end)
{
// Dereference 'begin' and do something.
++begin;
}
}
As mentioned above, using iterators means that a templated function can be used on any container that is 'iterateable'.
Code:
template typename <TIterator>
void Function(TIterator begin, const TIterator &end)
{
while (begin != end)
{
// Dereference 'begin' and do something.
++begin;
}
}
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|