明明初始化迭代器指向第一个元素,为什么它会指向最后一个元素的下一位?

#include <iostream>
#include <map>
using namespace std;

int main()
{
    map<char, int> myMap;
    map<char, int>::iterator i = myMap.begin();
    myMap['a'] = 1;
    myMap['b'] = 2;
    myMap['c'] = 3;
    cout << myMap.size()<<endl;
    if (i == myMap.end())
        cout << "i==myMap.end()\n";
    return 0;
}

输出:

3

i==myMap.end()

为什么会这个样子???

为什么会这样?很明显,是因为你使用了过期的迭代器i

请牢记一个原则:不要使用过期的iterator(迭代期间都应该指向最新的引用)

使用STL的iterator时的其他注意事项:

1)要理解迭代器的本质
iterator相当于指向节点的指针,无论迭代的容器对象是否发生改变,比如插入了新数据,或者有数据被删除等,该指针指向的内存地址不会被改变。

2)要注意迭代对象(容器)的自身特性,小心迭代器可能会失效
比如使用vector::iterator时,vector容器的每一次移动、增加、插入、删除以及reserve、resize等操作,都可能导致iterator指向的那块内存在容器操作过程中已经被其他内存覆盖或者内存已经被释放,即迭代器(指针)可能已经失效了。

// 举例说明:
vector<int> v;
vector<int>::iterator i = v.begin(); //试图获取第一个元素迭代器,此时*i等于v.begin()也等于v.end();
v.push_back(1);                              //加入第一个元素后,因为预留不够,所以发生内存搬移,之前迭代器i已经失效

3)要留意不同编译器的特异性
如果迭代的容器在循环迭代期间发生了改变,那么不同编译器可能会有不同的结果。比如,使用P.J.STL编译可以通过,而使用SGI STL库则编译不过哦。又比如,有的编译器对erase()语句总是返回下一元素的位置,而有的编译器则可能不是返回下一个元素的位置


/**
  *  对你的代码解读
  */
// 定义一个空map容器
map<char, int> myMap;

// 初始化迭代器,并指向第一个元素
// 请注意,迭代器指向空map对象时,myMap.begin()和myMap.end()指向同一块内存地址
map<char, int>::iterator i = myMap.begin();

// 对map容器的赋值语句
// 对map对象赋值时,并不能影响到迭代器指针。此时 i 仍然指向myMap.end()位置
myMap['a'] = 1;
myMap['b'] = 2;
myMap['c'] = 3;

// ...
// 下面的if语句为true
if (i == myMap.end()) 
{
    // ...
}
// ...

猜测你要实现的逻辑,可以调整一下语句顺序就可以了,代码如下:


#include <iostream>
#include <map>
using namespace std;

int main()
{
    map<char, int> myMap;
    myMap['a'] = 1;
    myMap['b'] = 2;
    myMap['c'] = 3;

    // 迭代器赋值语句放在map对象赋值语句的后面
    map<char, int>::iterator i = myMap.begin();

    cout << myMap.size()<<endl;
    if (i == myMap.end())
        cout << "i==myMap.end()\n";
    return 0;
}

修改后,输出结果:

输出:
3

if (i == myMap.end())
并不能说明它会指向最后一个元素的下一位

它只是调用了map的==运算符,比较i和myMap.end()这两个对象迭代器的状态

 map<char, int>::iterator i = myMap.begin();
map<char, int>::iterator j = myMap.end();
    ...
    if (i == j) ...

这样也是true