今天無論如何要寫點東西,算是搞清楚了一點東西吧。有點小小的成就感。 之前在程序里面使用了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進行操作是非法的,程序會出錯。