vector迭代器失效学习总结

2 篇文章 0 订阅
1 篇文章 0 订阅

学一学C++:vector迭代器失效学习小结

什么是迭代器失效?
我理解的迭代器失效,是指迭代器不能正确指示我们想要操作的对象了,对迭代器进行的操作会产生错误的结果。我们举个栗子来看看迭代器失效是怎么回事~

// 先定义一个用来输出vector<string>对象的函数show_vec
void show_vec(vector<string>::iterator first, vector<string>::iterator last)
{
    while(first != last)
    {
        std::cout << *first << " ";
        first++;
    }
    std::cout << " " << std::endl;
}

我们来看一个会使迭代器失效的栗子~

int main()
{
    vector<string> vecString;			// 定义一个空的vector<string>对象vecString
    string name;						// 定义一个空的string对象name
    while(cin>>name)					// 向vecString输入元素
        vecString.push_back(name);
    show_vec(vecString.begin(), vecString.end());	// 调用show_vec函数输出vecString

    vector<string>::iterator i;
    for(i=vecString.begin(); i!=vecString.end() ; i++)	// 这个循环会出问题
    {
        if (*i == "LiHonghe")
            vecString.erase(i); 
    }
    show_vec(vecString.begin(), vecString.end());
    return 0;
}

看一下它的输入和对应的输出结果。注意到我输入了两次“LiHonghe”,然而它只删除了一次,问题来了这个栗子是怎么失效的呢?
在这里插入图片描述下面我们详细分析一下迭代器在循环中是怎么变化的。

元素LiHongheLiHongheLiLuLiJiaxinLiMingLiDongbiao
下标012345

我们用“iter”和“↓”来表示当前迭代器。

iter↓
元素LiHongheLiHongheLiLuLiJiaxinLiMingLiDongbiao
下标012345

进入循环,我们发现第一个元素是“LiHonghe”,需要使用erase成员函数删除它(见erase的执行条件)。erase成员函数如何删除元素,对于我们分析iter的变化至关重要,因此我们要插播一下erase的实现方法(仅分析删除单个元素的情况)。

iterator erase(iterator position)
{
    if(position + 1 != end())				// 如果下一个位置不是“尾后”
        copy(position + 1, finish, position);// 将position+1至finish的元素移到position至finish-1
    --finish;							// 新finish是原finish的前一位
    destroy(finish);					// 删除原finishi
    return position;					// 返回position
}

看完代码我们可以知道,erase在删除元素的时候,是把该元素后边的所有元素向前移动一位,而返回的迭代器还是原来的迭代器。所以在删除“LiHonghe”之后,迭代器“iter”还在下标“0”的位置。

iter↓
元素LiHongheLiLuLiJiaxinLiMingLiDongbiao(destroy)
下标012345

回到循环,当我们删除完“LiHonghe”之后系统会执行“iter++”操作,这使“iter”移到“LiLu”,也就错过了第二个“LiHonghe”。因此我们在进入循环中,不满足if (*i == “LiHonghe”)的执行条件,这就使得输出中还有一个“LiHonghe”存在。迭代器也就失效了。

iter↓
元素LiHongheLiLuLiJiaxinLiMingLiDongbiao(destroy)
下标012345

更改它的方法,就是把对迭代器的操作,同循环体分开。局部代码更改如下:

for(i=vecString.begin(); i!=vecString.end() ; )	// 将i++与erase分开执行,这个循环就没问题了
{
    if (*i == "LiHonghe")
        vecString.erase(i); 			// 执行erase,则不执行i++
	else
		i++;						// 不执行erase,则执行i++
}

有的人把vecString.erase(i)写成i = vecString.erase(i),我们知道erase的返回值是迭代器,不过经过刚才的分析,我们知道i是不变的,所以用不用返回值重新给i赋值,对结果没有影响。输出结果如下:
在这里插入图片描述这样重复的“LiHonghe”就被删除啦。
使得vector迭代器失效的操作有:
(1)执行erase方法时,指向删除节点及其之后的全部迭代器均失效;
(2)执行push_back方法时,end操作返回的迭代器失效;
(3)插入一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时begin和end操作返回的迭代器都会失效;(capacity是指在发生realloc前能允许的最大元素数,即预分配的内存空间)
(4)插入一个元素后,如果空间未重新分配,指向插入位置之前的元素的迭代器仍然有效。
(其中,第三条我不是很理解,因为还没有遇到改变capacity返回值的情况)
谨记,但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
其他容器的迭代器失效还没学习~目前就总结了vector。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值