[C++]vector迭代器失效

发布于:2025-06-24 ⋅ 阅读:(20) ⋅ 点赞:(0)

目录

开头:

1.什么是迭代器失效

2.为什么会出现迭代器失效

2.1 insert

2.2 erase

3.总结


开头:

我们想要去了解为什么会有迭代器失效,我们就要先去了解vector中的迭代器是怎么去实现的.

迭代器可能是一个类也可能是原生的指针,list的迭代器就是一个类来实现的,而我们的vector中的迭代器是用原生指针来实现的.

typedef T* iterator;
typedef const T* const_iterator;
 

这里的T指的是模版参数.

1.什么是迭代器失效

       这里的vector中的迭代器是原生的指针,所以出现迭代器失效有以下情况.

1.野指针(指向非法的空间)和空指针

2.迭代器的指向有问题

2.为什么会出现迭代器失效

        常见的迭代器失效有多种情况insert和erase,push_back等会导致迭代器失效.

        2.1 insert

        我们来看一下我们模拟实现的insert是怎么样的.

void insert(iterator pos , const T& x) {    
    //判断迭代器位置是否合法
	assert(pos >= _start && pos <= _finish);	
    //判断是否需要扩容			
	if (_finish == _end_of_storage) {
	    size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);		
	}
    //移动数据
	iterator end = _finish - 1;
	while (end >= pos) {
		*(end + 1) = *end;
		--end;
	}
	_finish++;
	*(pos) = x;
}

        我们在插入数据的时候会出现问题而且这个问题是偶然发生的.

        我们看两种情况一个插入成功,一个出现了随机值是为什么?想要去明白为什么,就要去理解vector的内部insert实现是什么情况.

        第一种情况没有出现问题是以为没有发生扩容,第二中情况发生了问题是因为发生了扩容.发生了扩容就会导致野指针的问题.

        第一种情况:

        第二中情况:

        我们看到扩容之后会导致野指针的问题,pos还是指向原来的位置而_start和_finish指向新的空间.会导致我们的循环不进去_finish直接加加,对pos的解引用不会影响到新的空间.所以会出现随机值.

        解决方法:

我们只需要保存pos到_start的距离,就是size_t sz = pos - _start. 扩容完成之后再加上就可以了. pos = _start + sz; 就是要修改pos的位置.在返回pos位置的迭代器就可以了.

        修改后的代码:


iterator insert(iterator pos , const T& x) {    
    //判断迭代器位置是否合法
	assert(pos >= _start && pos <= _finish);	
    //判断是否需要扩容			
	if (_finish == _end_of_storage) {
        //保存pos到_start的距离
        size_t sz = pos - _start;
	    
        size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);
        //更新pos的位置
        pos = _start + sz;
	}
    //移动数据
	iterator end = _finish - 1;
	while (end >= pos) {
		*(end + 1) = *end;
		--end;
	}
	_finish++;
	*(pos) = x;

    return pos;
}

        修改成功就能正常插入了.

        2.2 erase

                 erase删除不会出现野指针的问题,会出现迭代器的指向失效的问题.

                我们可以看一下erase的内部实现.

void erase(iterator pos) {
	assert(pos >= _start && pos < _finish);
	if (_start) {
		iterator end = pos + 1;
		while (end < _finish) {
			*(end - 1) = *end;
			 end++;
		}
		--_finish;
	}
}

               例如我们要删除vector中所有的偶数,

        

          这个就是典型的迭代器指向发生改变导致迭代器失效.我们来分析一下为什么会有迭代器失效.

        那么我们应该要怎么去解决这个问题呢?我们可以返回删除完成之后pos位置的迭代器这样就完成了.

        修改后的代码:

​
iterator erase(iterator pos) {
	assert(pos >= _start && pos < _finish);
	if (_start) {
		iterator end = pos + 1;
		while (end < _finish) {
			*(end - 1) = *end;
			 end++;
		}
		--_finish;
	}
    return pos;
}

​

        我们看这样结果就正确了.

3.总结

        迭代器使用之后,不要在重复使用否则会导致迭代器失效.


网站公告

今日签到

点亮在社区的每一天
去签到