您的位置:首页 > 编程语言 > C语言/C++

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的真正操作应该是了然于胸了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: