C++ vector容器erase操作后iterate失效真相
2015-07-23 12:39
357 查看
在使用STL Vector容器时,大家一定遇到进行erase操作后,迭代器会失效的现象。网上很多文章解释说,是因为Vector的底层是通过数组来实现的,erase之后会造成内存的重新分配,故原容器的迭代器便失效。 我以前也一直这样认为,从来没有深究过,最近在研读《STL 源码剖析》的第四章时,发现如下代码:
iterator erase(iterator postion)
{
if (position + 1 != end())
{
copy(position+1, finish, position);
}
--finish;
destroy(finish);
return position;
}
从上述代码可以看到,返回的postion就是输入的迭代器,如果其失效,那返回的结果岂不是也是失效的。那诸如 iter = vector.erase(iter)的代码焉能work??? 其实上述代码中,并没有发生内存的重新分配,只是将position后面的所有元素向前移动一个位置,再将最后一个元素删除并释放内存,所以,原position的位置并没有发生变化,输入迭代器本身并没有失效。那就奇怪了,为何 如下的代码,无法正常工作呢:
for (iter = vector.beng(); iter != vector.end(); ++iter)
{
// 判断条件
{
vector.erase(iter);
}
}
于是,我在VS2012中重新验证上了上述代码,执行完erase操作后,再执行++iter操作,便crash掉了,另一个疑问又来了,即使iter失效,那么(*iter)操作确实会引起crash,但++iter操作不应该引起crash呀,仔细看了VS的出错信息 ”Expression: vector iterator not incrementable“, 人家只是说iter不能递增,并没有说iter指正非法访问!!!
打开VS的vector源码,发现erase的代码如下:
iterator erase(const_iterator _Where)
{ // erase element at where
if (_VICONT(_Where) != this
|| _VIPTR(_Where) < this->_Myfirst
|| this->_Mylast <= _VIPTR(_Where))
_DEBUG_ERROR("vector erase iterator outside range");
_Move(_VIPTR(_Where) + 1, this->_Mylast, _VIPTR(_Where));
_Destroy(this->_Mylast - 1, this->_Mylast);
_Orphan_range(_VIPTR(_Where), this->_Mylast);
--this->_Mylast;
return (_Make_iter(_Where));
}
基本思路和SGI的没什么两样,先移动覆盖,再删除释放,那为什么会crash掉呢,问题就出在了erase的输入上,看到了没有,erase的输入是 (const_iterator _Where),是const_iterator,没错,都是const_iterator惹得祸呀,在return语句中(_Make_iter(_Where))便是将_Where变成了普通的iterator,其代码如下:
iterator _Make_iter(const_iterator _Where) const
{ // make iterator from const_iterator
return (iterator(_Where._Ptr, this));
}
至此,大家对erase操作对iterator的真正操作应该是了然于胸了。
iterator erase(iterator postion)
{
if (position + 1 != end())
{
copy(position+1, finish, position);
}
--finish;
destroy(finish);
return position;
}
从上述代码可以看到,返回的postion就是输入的迭代器,如果其失效,那返回的结果岂不是也是失效的。那诸如 iter = vector.erase(iter)的代码焉能work??? 其实上述代码中,并没有发生内存的重新分配,只是将position后面的所有元素向前移动一个位置,再将最后一个元素删除并释放内存,所以,原position的位置并没有发生变化,输入迭代器本身并没有失效。那就奇怪了,为何 如下的代码,无法正常工作呢:
for (iter = vector.beng(); iter != vector.end(); ++iter)
{
// 判断条件
{
vector.erase(iter);
}
}
于是,我在VS2012中重新验证上了上述代码,执行完erase操作后,再执行++iter操作,便crash掉了,另一个疑问又来了,即使iter失效,那么(*iter)操作确实会引起crash,但++iter操作不应该引起crash呀,仔细看了VS的出错信息 ”Expression: vector iterator not incrementable“, 人家只是说iter不能递增,并没有说iter指正非法访问!!!
打开VS的vector源码,发现erase的代码如下:
iterator erase(const_iterator _Where)
{ // erase element at where
if (_VICONT(_Where) != this
|| _VIPTR(_Where) < this->_Myfirst
|| this->_Mylast <= _VIPTR(_Where))
_DEBUG_ERROR("vector erase iterator outside range");
_Move(_VIPTR(_Where) + 1, this->_Mylast, _VIPTR(_Where));
_Destroy(this->_Mylast - 1, this->_Mylast);
_Orphan_range(_VIPTR(_Where), this->_Mylast);
--this->_Mylast;
return (_Make_iter(_Where));
}
基本思路和SGI的没什么两样,先移动覆盖,再删除释放,那为什么会crash掉呢,问题就出在了erase的输入上,看到了没有,erase的输入是 (const_iterator _Where),是const_iterator,没错,都是const_iterator惹得祸呀,在return语句中(_Make_iter(_Where))便是将_Where变成了普通的iterator,其代码如下:
iterator _Make_iter(const_iterator _Where) const
{ // make iterator from const_iterator
return (iterator(_Where._Ptr, this));
}
至此,大家对erase操作对iterator的真正操作应该是了然于胸了。
相关文章推荐
- K-Mean聚类算法+C语言代码
- C++中的多态问题
- C++ transform 浅析
- vim 打造 C/C++ IDE
- C语言,快速排序算法
- leetcode 日经贴,Cpp code -Search a 2D Matrix II
- VS2013 配置全局 VC++ 目录
- (三十)C语言学习笔记(一)——类型、运算符与表达式
- C++中构造函数、复制构造函数和赋值操作符
- 自己写了个C++计时器类,可用作秒表和计时
- c++之内联函数以及宏定义
- VC++ MFC如何生成一个可串行化的类
- c语言return机制
- 简单分析C++指针的操作和运算
- 指针,数组,字符串的区别(高质量程序设计指南C++/C语言第7章)
- 一步步将vim改造成C/C++开发环境(IDE)
- 读书笔记MoreEffectiveC++(四)
- C/C++中的经典排序算法总结
- C/C++中的经典排序算法总结
- Num 7 : C语言中的各种排序方法