STL中list的erase()使用注意
erase()方法是删除iterator指定的节点 ,链表容器使用erase删除节点还有一个特点,就是会将下一个元素的地址返回。但是要注意的是在执行完此函数的时候iterator也被销毁了,这样的话关于iterator的操作就会报错 ,以下是关于erase()方法的正确使用:
正确使用方法1 : std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{if( WillDelete( *itList) ){itList = List.erase( itList);}elseitList++;
}换个写法:
std::list< int>::iterator itList;
itList=List.begin();
while(itList != List.end()){if(WillDelete(*itList)){itList=List.erase(itList);contine;//跳过本次循环}itList++;
}
正确使用方法2 : std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{if( WillDelete( *itList) ){List.erase( itList++);}elseitList++;
}
错误使用方法1: std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); itList++)
{if( WillDelete( *itList) ){List.erase( itList);}
}
问题:该程序不能跳出循环
原因:List.erase(itlist);每次做erase时都有可能使迭代器失效,itList++就发生错误了。
可以参见effective stl一书。所有容器做erase操作时都有可能使迭代器失效。//会出现野指针问题,这是因为erase的自加+1导致的,当erase最后一个时,本应结束结果自加+1后又遇上
itList++因此出现越界,出现野指针问题。
错误使用方法2 : std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{if( WillDelete( *itList) ){itList = List.erase( ++itList);}elseitList++;
}
先前list容器,用到了erase()函数,之前一直没出现问题,最近突然莫名出问题。搞清楚了erase()函数的机理。
常用的删除容器中元素的方法是如下(方法1):list< int> List;list< int>::iterator iter;for( iter = List.begin(); iter != List.end(); ){if(1) {iter = List.erase( iter );}else{iter++;}}也可以这样写(方法2):list< int> List;list< int>::iterator iter;for( iter = List.begin(); iter != List.end(); ){if(1) {List.erase( iter++ );}else{iter++;}}有一种错误的写法(注意同方法2比较)list< int> List;list< int>::iterator iter;for( iter = List.begin(); iter != List.end(); ){if(1) {List.erase( iter );}iter++;}我们看一下erase()函数的源代码(仅列出release下的代码)。iterator erase(iterator _Where){ // erase element at _Where_Nodeptr _Pnode = (_Where++)._Mynode();if (_Pnode != _Myhead){ // not list head, safe to erase_Nextnode(_Prevnode(_Pnode)) = _Nextnode(_Pnode);_Prevnode(_Nextnode(_Pnode)) = _Prevnode(_Pnode);this->_Alnod.destroy(_Pnode);this->_Alnod.deallocate(_Pnode, 1);--_Mysize;}return (_Where);}函数在返回的时候,是返回当前迭代器的下一个节点。所以当 iter = List.erase( iter ); 执行以后,迭
代器自动指向了下一个元素。而对于入参中的iter,所指的地址已经被销毁,所以写的时候,应该注意加上前面的iter =
那另外的一种写法,List.erase( iter++ ); 为什么也是对的呢?
这里研究了一下,这里需要讲一下++运算符的操作。_Myt_iter& operator++() { // preincrement++(*(_Mybase_iter *)this);return (*this);}_Myt_iter operator++(int) { // postincrement_Myt_iter _Tmp = *this;++*this;return (_Tmp);}++实际上可以看做是一个函数。
对于++在后的情况(例如i++),函数在运行的时候,将运算的数据i已经改变,但是函数的返回值是操作之前
的数据,所以在我们看来,i++好像是先进行了i的读取,才+1。回到迭代器,List.erase( iter++ );就没有问题了。对于那种错误的方法,List.erase( iter );在执行以后,iter所指的对象已经被销毁,所以再对iter进行操
作是非法的,程序会出错。
参考:
https://blog.csdn.net/jfkidear/article/details/40822291
http://blog.sina.com.cn/s/blog_782496390100rtyp.html
https://www.cnblogs.com/fnlingnzb-learner/p/5892584.html
https://blog.csdn.net/IEEEITU/article/details/6723187?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-4
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
