类标准库的使用
#include <iostream>#include <string>
#include <vector>
using namespace std;
int main()
{
vector<int> lst = {1,101,2,303,4,404,6,707,9,909,1001};
auto it = lst.begin();
while(it != lst.end())
{
if (*it %2)
{
lst.erase(it); # 在这一行C++primer中的书写方式是 it = lst.erase(it);
}
else
{
++it;
}
}
for (auto it1 = lst.begin() ; it1 != lst.end();++it1)
{
cout << "####################" << endl;
cout << *it1 << endl;
cout << "####################" << endl;
}
return 0;
}
question:
不写it = 的方式和书写了的方式有何不同? 为什么要写上那一步?
本帖最后由 Croper 于 2019-1-25 12:21 编辑
erase返回的是指向被删除元素后面的那个位置,
如对于{1,2,3,4},此时it指向2,那么erase(it),原来的vector变成{1,3,4},并且erase返回一个指向3的迭代器,
如果不写it=的话,
那么你erase(it)之后,it就成为了野指针(野迭代器?),之后的操作会全部失效 Croper 发表于 2019-1-25 12:01
erase返回的是指向被删除元素后面的那个位置,
如对于{1,2,3,4},此时it指向2,那么erase(it),原来的vector ...
然而得到的结果是一样的 我试了下 对于某些比较宽松的编译器,按现版本的vector存储方式,确实结果应该是一样的,
但这只对vector等少数基于数组存储的容器有效,且仅在某些比较宽松的编译器中有效,(在vs 2017中会报错)
需要解释的话,首先了解一下vector是如何存储元素的
作为一个变长数组,当向其存储数据时,vector会申请一段默认长度的空间,比方说,对于一个储存了{1,2,3}的vector,它内部可能是这样的
{1,2,3,0},size=3;这个时候,向其添加一个元素4,它会变成这样{1,2,3,4},size=4,这个时候,1,2,3的地址都没有改变,那么指向其的指针均保持有效;
但是,这个时候再向其添加一个元素5,因为原来的数组已经不够大,vector会申请一段更大的空间,比如int,并把原来的元素搬过去,就变成了这样
{1,2,3,4,5,0,0,0},size=5;这个时候,指向原1,2,3的指针,其地址已经被释放,也就是变成了野指针。
但是现版本的vector,在删除元素时,并不会发生容量的减少,所以指针总是有效;
但是,迭代器并不仅仅是指针,而是包装了的指针,当你调用erase(it)时,it会直接被标记为“失效”,因而对于某些编译器,会因为你调用了“失效”了的迭代器而报错,
此外,你并不能保证,在下个版本中,vector不会因为erase而减少容量;
第三,对于其他容器,比如基于链表的容器,这种用法一定失败。
因此,即使在这个例子中成功了,你也不应该试图调用一个失效了的迭代器
Croper 发表于 2019-1-25 14:00
对于某些比较宽松的编译器,按现版本的vector存储方式,确实结果应该是一样的,
但这只对vector等少数基于 ...
十分感谢您的回复
页:
[1]