I h开发者_运维知识库ave been using map/vector extensively these days, but have a doubt in iterating them
Which one is better?
for(vector<string>::iterator it=myvec.begin(); it!=myvec.end(); ++it){
}
or
for(int i=0; i < myvec.size(); i++){
myvec[i]
}
First of all, are they meant to do the same thing?
Both will work equally well for iterating over a vector. I have a preference for iterators, because I have seen bad things done with indices -- mainly someone using the index of one container to reach into a different container. If the second container is smaller, this won't work.
If you're just trying to do something for each element, you can use BOOST_FOREACH.
std::list<int> list_int( /*...*/ );
BOOST_FOREACH( int i, list_int )
{
// do something with i
}
When you use manual loop, it doesn't make much difference. But when you work with STL functions (say functions from <algorithm>
), you don't have choice. You've to use iterator, as STL functions work with iterator, not with index.
For example, if you want to calculate sum of all integers in a vector<int>
using std::accumulate
, then you've to do this:
int sum = std::accumulate(vints.begin(),vints.end(),0);
So my suggestion would be : make habit of using iterators, as it gives you uniformity and also gradually makes you comfortable with the philosophy of iterators. It gives a sense of genericity!
It depends on if you need to know the position of the element within its container while performing the body of the loop. If you do, you need to use the second form. If not, use the first, because it's more generic and therefore more flexible; you could change the type of myvec
to anything that supports iterators, even if it doesn't support random access.
from Meyers "Effective STL", item 43.
"Prefer algorithm calls to hand-written loops"
- algorithms are often more efficient than the loops programmers produce
- writing loops is more prone to errors
- algorithm code is easier to read
use algorithms with iterators as often as possible.
std::for_each(myvec.begin(), myvec.end(), [](const string& s) {
/* your code here */
});
I try to hide the underlying implementations of my containers as much as possible.
So in your example, I would start by using a typedef instead of referring directly to the vector (later you will see why):
typedef std::vector<string> MyStringCollection;
Then, I try to use constructions that rely as little as possible on the underlying implementation. In this case, I want to iterate over the container and use the values in the container, like this:
for(MyStringCollection::iterator it=mycollection.begin(); it!=mycollection.end(); ++it)
{
// use *it
}
With the typedef the users of your collection only have to use MyStringCollection::iterator
without needing to know what MyStringCollection actually is.
Note that in C++0x, you could use auto
, which is even shorter (making my argument for the typedef less relevant).
The advantage of this is that now becomes quite easy to change MyStringCollection from std::vector to std::list. If because of performance reasons you decide that a list would be better suited, you only have to:
- Change the typedef from std::vector to std::list
- Have a quick look to all the places where MyStringCollection is being used (which will be easier to find than looking up all uses of std::vector
精彩评论