STL關聯式容器中刪除元素的方法和陷阱 四 (轉)
在STL(標準模板庫)中經常會碰到要刪除容器中部分元素的情況,本人在中就經常編寫這方面的程式碼,在編碼和測試過程中發現在STL中刪除容器有很多陷阱,網上也有不少網友提到如何在STL中刪除元素這些問題。
上一篇文章主要討論序列式容器vector、list中安全刪除元素的方法和可能會遇到的陷阱,這一次討論在map(multimap)容器中如何安全的刪除和插入元素。
map(multimap)容器為關聯式容器,是程式設計中經常使用的容器,有鍵值(key)和實值(value),又稱字典、對映表。
你能看出以下程式碼有什麼問題?
例1:
#pragma warning (disable : 4786)
#include
#include
using namespace std;
void main() {
map< int, int* > mnt;
for ( int i = 0; i < 5; i++ ) {
mapInt[ i ] = new int( i );
}
// 再插入鍵值為2的元素
mapInt[ 2 ] = new int( 2 );
// 做一些操作
// 刪除。
map< int, int* >::iterator itMap = mapInt.begin();
for ( ; itMap != mapInt.end(); ++itMap ) {
delete itMap->second;
}
}
:namespace prefix = o ns = "urn:schemas--com::office" />
例2:
void main() {
map< int, int* > mapInt;
for ( int i = 0; i < 5; i++ ) {
mapInt.insert( make_pair( i, new int( i ) ) );
}
// 再插入鍵值為2的元素
mapInt.insert( make_pair( 2, new int( 2 ) ) );
// 做一些操作
// 刪除記憶體。
map< int, int* >::iterator itMap = mapInt.begin();
for ( ; itMap != mapInt.end(); ++itMap ) {
delete itMap->second;
}
}
例3:
void main() {
map< int, int > mapInt;
for ( int i = 0; i < 5; i++ ) {
mapInt.insert( make_pair( i, i ) );
}
mapInt.insert( make_pair( 5, 2 ) );
// 刪除所有實值為2的元素
map< int, int >::iterator itMap = mapInt.begin();
for ( ; itMap != mapInt.end(); ++itMap ) {
if ( itMap->second == 2 ) {
mapInt.erase( itMap );
}
}
}
分析:
例1將導致記憶體洩露,因為mapInt[ 2 ] = new int( 2 );這條語句把原來鍵值為2的元素的實值指標覆蓋了,原來的指標就成為野指標,導致記憶體洩露。
例2也將導致記憶體洩露,因為mapInt.insert( make_pair( 2, new int( 2 ) ) );這條語句因為鍵值為2的元素已經存在,導致插入元素失敗,所以指向剛分配的記憶體的指標成為野指標,導致記憶體洩露。
map容器插入元素的方法。可以map容器的insert成員插入元素,或者直接用map容器的下標運算式賦值,但這裡有一個地方要注意,如果實值為指標的話,插入重複鍵值的元素時,會導致記憶體洩露。所以對於插入元素時,必須檢查是否插入成功。
正確的方法:
void main() {
map< int, int* > mapInt;
bool bRet;
for ( int i = 0; i < 5; i++ ) {
int* pI = new int( i );
bRet = mapInt.insert( make_pair( i, pI ) ).second;
if ( !bRet ) {
// 插入元素不成功。
delete pI;
}
}
// 再插入鍵值為2的元素
int* pI = new int( 2 );
bRet = mapInt.insert( make_pair( 2, pI ) ).second;
if ( !bRet ) {
// 插入元素不成功。
delete pI;
}
// 做一些操作
// 刪除記憶體。
map< int, int* >::iterator itMap = mapInt.begin();
for ( ; itMap != mapInt.end(); ++itMap ) {
delete itMap->second;
}
}
例3將導致未定義的錯誤,在中即是訪問記憶體,程式當掉。因為mapInt.erase( itMap );呼叫後itMap迭代器已無效了,所以當++itMap時,訪問非法記憶體,導致程式當掉。
如果erase()總是返回下一元素的位置,那就可以像在vector容器中刪除元素一樣,如:
// 刪除所有實值為2的元素
map< int, int >::iterator itMap = mapInt.begin();
for ( ; itMap != mapInt.end(); ) {
if ( itMap->second == 2 ) {
itMap = mapInt.erase( itMap );
}
else {
++itMap;
}
}
但是,注意,以上的方式只在vc使用P.J.STL中才能編譯透過,而使用SGI STL庫則編譯不過,因為SGISTL庫在設計中考慮到如果不需要這一特性,就會損失,因此否決了這種想法。所以要保證可移植性,最好採用下面的方法:
// 刪除所有實值為2的元素
map< int, int >::iterator itMap = mapInt.begin();
for ( ; itMap != mapInt.end(); ) {
if ( itMap->second == 2 ) {
// itMap++將使itMap指向下一個元素,但返回原迭代器的副本,所以
// erase()被呼叫時,itMap不指向將要被刪除的元素
mapInt.erase( itMap++ );
}
else {
++itMap;
}
}來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993405/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- STL序列式容器中刪除元素的方法和陷阱 一 (轉)
- STL.vector容器刪除單個元素、部分元素、全部元素
- STL容器的各個函式方法函式
- oracle中的級聯刪除(轉)Oracle
- PHP從陣列中刪除元素的方法PHP陣列
- 建立元素和刪除元素
- 關於javascript中陣列元素刪除問題的討論 (轉)JavaScript陣列
- Python 中刪除列表元素的三種方法Python
- 刪除內聯元素之間的空隙
- 關聯式容器set和map原理
- Java ArrayList刪除特定元素的方法Java
- Java刪除ArrayList中的重複元素的2種方法Java
- 批量刪除容器和映象
- JavaScript 建立和刪除元素JavaScript
- ArrayList元素的刪除(4種函式)函式
- MySQL 多表關聯刪除MySql
- Oracle 多表關聯刪除Oracle
- 刪除元素的指定的class樣式類
- docker 批量刪除容器和映象Docker
- 三種方法刪除列表中重複的元素及效率分析!
- 如何刪除ArrayList中的重複元素
- laravel 多對多關聯刪除中間表Laravel
- Python列表刪除元素的方法有哪些?Python
- stl中各種容器的自定義比較函式函式
- js利用正規表示式刪除陣列中的重複元素JS陣列
- 進階篇_STL中的容器
- javascript刪除元素節點removeChild()函式JavaScriptREM函式
- docker刪除所有容器和映象命令Docker
- 關於二叉樹的前序遍歷、中序遍歷、刪除元素、插入元素二叉樹
- js刪除陣列中重複的元素JS陣列
- js刪除陣列中的重複元素JS陣列
- js刪除陣列元素中的指定值JS陣列
- JS] JS 之刪除陣列中的元素JS陣列
- 刪除陣列中的元素(連結串列)陣列
- jQuery為元素新增和刪除classjQuery
- jQuery如何新增和刪除元素jQuery
- JS刪除陣列裡的某個元素方法JS陣列
- jQuery刪除元素jQuery