您的位置:首页 > 其它

STL—list

2015-09-01 09:57 197 查看
之前在程序里面使用了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进行操作是非法的,程序会出错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: