序列式迭代器失效
迭代器是我们日常写代码时经常用到的,下面我们就定义迭代器
vector<int>::iterator it;;
cout << sizeof(it) << endl;
迭代器可以理解为我们对其的指针的操作,这就可以把it理解为一个指针,但是指针在32位机器上是占4个字节,在64位机器上占8个字节,“迭代器指针”不是4个也不是8个而是12个字节。
下来我们就看看vector迭代器失效。
int main()
{
vector<int> v;
for (int i = 0; i < 5; i++)
{
v.push_back(i);
}
v.push_back(4);
for (int i = 5; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it;;
cout << sizeof(it) << endl;
it = v.begin();
for (it; it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
it = v.begin();
for (it; it != v.end(); it++)
{
if (4 == *it)
{
v.erase(it);
}
}
it = v.begin();
for (it; it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
例如vector、deque都是序列式容器,由于序列式容器是组合式容器,方前一个元素的iterator被删除后,其后的所有元素的迭代器都会失效,这是因为vector、deque都是连续存储的一段空间,所以当对其进行erase操作时,其后的每一个元素都会向前移动一个位置。
上面的代码会奔溃,原因就在于迭代器失效。进行erase操作的迭代器已经失效了,失效的迭代器不能进行++操作,所以程序崩溃了。但是vector的erase操作可以返回下一个有效的迭代器,所以我们每次讲下一个有效迭代器返回就可以顺利指向后面的操作了。
修改后的代码如下:
int main()
{
vector<int> v;
for (int i = 0; i < 5; i++)
{
v.push_back(i);
}
v.push_back(4);
for (int i = 5; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it;;
cout << sizeof(it) << endl;
it = v.begin();
for (it; it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
it = v.begin();
for (it; it != v.end(); it++)
{
if (4 == *it)
{
it = v.erase(it);
}
}
it = v.begin();
for (it; it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
这段代码是不会崩溃的,执行的功能是将元素4用erase操作删除,但是结果却是只能删除一个元素4,第二个删除不了。上面提到进行erase操作后,后面的元素会自动向前移动一个位置,就相当于iterator指针会向后移动一个位置,在for循环中在++一下就会向后移动两个位置,所以说只能删除一个4,要想把4删除完可以在erase操作后增加it--就可以了,代码如下:
int main()
{
vector<int> v;
for (int i = 0; i < 5; i++)
{
v.push_back(i);
}
v.push_back(4);
for (int i = 5; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it;;
cout << sizeof(it) << endl;
it = v.begin();
for (it; it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
it = v.begin();
for (it; it != v.end(); it++)
{
if (4 == *it)
{
it = v.erase(it);
it--;
}
}
it = v.begin();
for (it; it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
这样就会将所以的4元素删除。
当然还可以用vector里面的remove函数进行上面代码的修改
关联迭代器失效
对于关联容器如map、set、multimap、multiset,删除当前的iterator,仅仅会让当前的iterator失效,只要在erase事,对当前的iterator++即可。因为map之类的容器,使用了红黑树来实现,插入或者删除一个结点不会对其他结点造成影响。
int main()
{
map<int,int> m;
for (int i = 0; i < 10; i++)
{
m.insert(make_pair(i,i*2));
}
map<int, int>::iterator it;
it = m.begin();
for (it; it != m.end(); it++)
{
cout << it->second << " ";
//cout << it->first << ":" << it->second << " ";
}
cout << endl;
it = m.begin();
for (it; it != m.end(); it++)
{
if (6 == it->second)
{
m.erase(it);
}
}
it = m.begin();
for (it; it != m.end(); it++)
{
cout << it->second << " ";
}
cout << endl;
return 0;
}
在删除了6元素之后,迭代器失效了,所以在进行++的时候奔溃。erase操作可以返回下一个有效的迭代器,所以需要加一个返回值就可以,或者迭代器自行++也就可以得到下一个有效的iterator;
修改后的代码如下:
int main()
{
map<int,int> m;
for (int i = 0; i < 10; i++)
{
m.insert(make_pair(i,i*2));
}
map<int, int>::iterator it;
it = m.begin();
for (it; it != m.end(); it++)
{
cout << it->second << " ";
//cout << it->first << ":" << it->second << " ";
}
cout << endl;
it = m.begin();
for (it; it != m.end(); it++)
{
if (6 == it->second)
{
m.erase(it++);
//it = m.erase(it);
}
}
it = m.begin();
for (it; it != m.end(); it++)
{
cout << it->second << " ";
}
cout << endl;
return 0;
}
这样就可以删去元素为6的元素使得迭代器不会失效。