4

当我像这样使用迭代器时,

//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++;
    }

}

输出为 4;

但是当我像这样使用迭代器时:

//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++;
    }

}

输出是我想要的;

我想知道使用迭代器有什么区别,当我插入新的键值对时,第一个迭代器发生了什么?谢谢!

补充: compile 是使用 gcc 4.1.2 ,感觉更困惑,像这样:

编译是使用 gcc 4.1.2 ,感觉比较混乱,像这样:

4

5 回答 5

10

由于您begin()在容器为空时调用,因此您得到了一个等于end()(第 23.1/7 节:“如果容器为空,则 begin() == end()”)的迭代器。

将项目插入容器并没有改变这一点,所以你仍然有pos == intIntMap.end().

然后,您执行循环的零次迭代,因为pos==end(),并且您只执行循环只要pos != end().

在第二个示例中,您pos()在插入数据后设置,因此您获取集合中的第一个项目,并迭代到最后一个项目。

编辑:就打印出地图的内容而言,我可能会这样做:

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"));
于 2012-06-24T03:56:20.703 回答
2

使用 gdb 进行检查,我发现first迭代器的字段随着每次添加键值对而发生变化。似乎没有数据的映射的迭代器(由返回begin())包含一些关于映射本身的元数据,特别是映射的大小(first所述迭代器的字段随着每次添加键值对而增长)。begin()在添加单个键值对后调用以检索迭代器会导致“预期”行为。

于 2012-06-24T03:51:10.300 回答
-1

迭代器旨在用于自迭代器实例化以来未修改的容器。根据 c++ 标准,第一个示例中的代码输出是未定义的(您仍然可以获得所需的结果,只是不能保证得到它,而且没有太多理由期待它)。

在第一种情况下,迭代器没有发生任何事情,但是您打算引用的容器发生了变化,并且不一定在内存中的同一位置。

于 2012-06-24T03:50:25.993 回答
-1

容器修改使现有迭代器无效。

通常的做法是在使用它之前获取迭代器,然后将其丢弃。你可以这样使用for

#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;
}
于 2012-06-24T03:56:12.340 回答
-1

简短回答:不保证迭代器在修改容器内容后仍然有效。

由于这里的容器是 a map,通常实现为红黑树,因此在插入过程中会修改和重新平衡结构。

在第一个示例中,您将迭代器初始化pos到地图的开头。此时,迭代器对当前内容有效。但是一旦你开始添加元素,迭代器就不再指向begin重组容器的新位置。

所以第二个示例有效的原因是因为您将迭代器设置为begin在对容器的所有修改完成之后。

一般来说,在迭代结构时修改结构是个坏主意。

这个问题有一些关于迭代器有效性的更多细节:

于 2012-06-24T03:56:46.867 回答