Reputation: 41
While I use iterator like this ,
//include header files
using namespace std;
int main()
{
map<int,int> intIntMap;
map<int,int>::iterator pos;
pos = intIntMap.begin();
intIntMap[0] = 1;
intIntMap[3] = 5;
intIntMap[4] = 9;
intIntMap[5] = 5;
//遍历
cout << (*pos).first << endl;
while( pos != intIntMap.end() )
{
cout << pos->first << " <---> " << pos->second << endl;
pos++;
}
}
The output is 4;
But while I use iterator like this:
//include header file
using namespace std;
int main()
{
map<int,int> intIntMap;
map<int,int>::iterator pos;
intIntMap[0] = 1;
intIntMap[3] = 5;
intIntMap[4] = 9;
intIntMap[5] = 5;
//遍历
pos = intIntMap.begin();
cout << (*pos).first << endl;
while( pos != intIntMap.end() )
{
cout << pos->first << " <---> " << pos->second << endl;
pos++;
}
}
The output is what I want;
I want to know what is the difference between use of iterator, what happended to the first iterator when I insert new key-value pair ? Thanks!
addtion: compile is use gcc 4.1.2 , in feel more confused,like this :
Upvotes: 4
Views: 958
Reputation: 490058
Since you called begin()
when the container was empty, you got an iterator that was equal to end()
(§23.1/7: "If the container is empty, then begin() == end()").
Inserting items into the container didn't change that, so you still have pos == intIntMap.end()
.
You then execute zero iterations of your loop, since pos==end()
, and you'r executing the loop only as long as pos != end()
.
In the second example, you set pos()
after you've inserted the data, so you get the first items in the collection, and iterate to the last.
Edit: As far as printing out the contents of the map goes, I'd probably do it more like this:
std::ostream &operator<<(std::ostream &os, std::pair<int, int> const &d) {
return os << d.first << " <---> " << d.second;
}
// ...
std::copy(intIntMap.begin(), intIntMap.end(),
std::ostream_iterator<std::pair<int, int> >(std::cout, "\n"));
Upvotes: 10
Reputation: 20018
Short answer: there is no guarantee that the iterator is still valid after modifying the container contents.
Since the container here is a map
, typically implemented as a red-black tree, the structure is modified and rebalanced during insertions.
In the first example, you are initialising the iterator pos
to the start of the map. At this point, the iterator is valid for the current contents. But once you start adding elements, the iterator is no longer pointing to the new begin
position of the reorganised container.
So the reason why the second example works is because you are setting the iterator to begin
after all modifications to the container have been completed.
In general, it is a bad idea to modify a structure while iterating over it.
This question has some more details on validity of iterators:
Upvotes: -1
Reputation: 4060
Container modification invalidates existing iterators.
The common practice is to get iterator just before using it, and then, throw it away. You could use for
like this:
#include <iostream>
#include <map>
using namespace std;
int main ()
{
map<int, int> mymap;
mymap[0] = 100;
mymap[1] = 200;
mymap[2] = 300;
// show content:
for (map<int, int>::iterator it = mymap.begin(); it != mymap.end(); it++)
cout << (*it).first << " => " << (*it).second << endl;
return 0;
}
Upvotes: -1
Reputation: 5559
Going through this with gdb, I found that the first
field of the iterator was changing with each addition of a key-value pair. It seems that an iterator to a map with no data in it (returned by begin()
) contains some metadata about the map itself, specifically the size of the map (the first
field of said iterator grew with each addition of a key-value pair). Calling begin()
to retrieve the iterator after a single key-value pair is added results in the "expected" behavior.
Upvotes: 2
Reputation: 374
Iterators are intended to be used on a container that has not been modified since the iterator instantiation. The code's output in the first example is undefined, according to the c++ standard (you could still get the result you want, you're just not guaranteed to get it, and there's not much of a reason to expect it).
Nothing happened to the iterator in the first case, but the container you intend it to refer to has undergone changes, and isn't necessarily at the same location in memory.
Upvotes: -1