list/map中安全删除元素


最近遇到在map中删除元素安全性的问题,于是查了查资料,记录一下。

问题的引出:一个关于list::erase()的问题。

    写了个小程序试验list在erase一个成员之后iterator 值的变化,程序中注释部分是运行结果显示的数据,代码如下(主要代码):
 
list<CStudent*>::iterator It;  
  
for(It = myList.begin(); It != myList.end(); )  
  
{  
  
 cout<<"It= "<<&(*It)<<endl;     // It= 0x00372320  
  
 myList.erase(It);  
  
 cout<<"It= "<<&(*It)<<endl;     // It= 0x00372320  
  
 It++;    
  
 cout<<"It= "<<&(*It)<<endl;     // It= 0xDDDDDDE5  
  
}


问题:
     It++之后为什么It值由0x00372320变为0xDDDDDDE5而不是指向下一个元素地址?
答案:
     看看数据结构就明白了,每一个节点包括数据部分和指针部分,指针指向下一个节点,如果iterator指向当前节点,移除当前元素之后,下一个元素的地址也丢失了,所以It++时找不到下一个元素。

移除list中的元素:

      List提供了两个函数用于移除成员:erase()和remove(),关于两个函数的用法可以参考MSDN,这里重点讲述用这两个函数时需要注意的问题。

注意点一、删除全部元素


错误写法:

for(It = myList.begin(); It != myList.end(); It++)  
{  
	myList.erase(It);  
}  

    本人刚开始就犯了上面这样的错误,学过数据结构的朋友知道,链表中的每个节点包括两部分,数据部分和指针部分,指针指向下一个节点的地址,当It指向当前节点并对当前节点进行删除操作时,下一节点的地址就丢失了,多么可怕! 

正确写法:

for(It = m_MyList.begin(); It != m_MyList.end();)    
{  
 list<CStudent*>::iterator It2;  
 It2 = It;  
 It++;  
  m_MyList.erase(It2);    
}  
注意,for循环里没有It++。

注意点二、当List成员在堆上创建时

先看下面一段代码:

list<CStudent *>myList;  
CStudent * pStudentA = new CStudent;  
  
StudentA->SetInfo(27, "StudentA");  
  
CStudent * pStudentB = new CStudent;  
  
StudentB->SetInfo(20, "StudentB");  

CStudent * pStudentC = new CStudent;  
  
StudentC->SetInfo(24, "StudentC");  

myList.push_back(pStudentA);  
  
myList.push_back(pStudentB);  
  
myList.push_back(pStudentC);  

list<CStudent*>::iterator It;  
for(It = myList.begin(); It != myList.end(); )  
{  
list<CStudent*>::iterator It2;  
It2 = It;  
It++;  
m_MyList.erase(It2);   
} 

    上面代码在堆上创建了三个对象,然后将三个对象加入队列,最后将对象erase,那还需不需要delete呢?答案是需要!erase不等同于delete,安全的做法是先delete再erase。

正确代码如下:

list<CStudent*>::iterator It;  
for(It = myList.begin(); It != myList.end(); )  
{  
list<CStudent*>::iterator It2;  
It2 = It;  
It++;  
Delete *It2;        // delete每个对象指针  
m_MyList.erase(It2);   
}  

     *It就是对象指针,不信的话可以打印出*It的值和StudentA的值比较一下,两个值相等。Delete *It2;一定要放在m_MyList.erase(It2);之前,因为m_MyList.erase(It2)执行之后节点被删除,*It2的值就被修改了。

在Java,在遍历 `List<Map>` 集合时增加或删除元素会抛出 `ConcurrentModificationException` 异常,因为增加或删除元素会改变集合的大小,从而影响到遍历的顺序和结果。 为了避免这个异常,可以使用迭代器的 `remove` 方法来删除元素,或者使用 `ListIterator` 来增加或删除元素。 下面是示例代码: ```java import java.util.*; public class Main { public static void main(String[] args) { List<Map<Integer, String>> my_list = new ArrayList<>(); my_list.add(new HashMap<>() {{ put(1, "one"); put(2, "two"); }}); my_list.add(new HashMap<>() {{ put(3, "three"); put(4, "four"); }}); my_list.add(new HashMap<>() {{ put(5, "five"); put(6, "six"); }}); // 增加元素 ListIterator<Map<Integer, String>> iterator = my_list.listIterator(); while (iterator.hasNext()) { Map<Integer, String> m = iterator.next(); m.put(7, "seven"); } // 删除元素 iterator = my_list.listIterator(); while (iterator.hasNext()) { Map<Integer, String> m = iterator.next(); if (m.containsKey(3)) { iterator.remove(); } } // 输出修改后的集合 for (Map<Integer, String> m : my_list) { for (Map.Entry<Integer, String> entry : m.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } } } } ``` 输出结果为: ``` 1: one 2: two 5: five 6: six 7: seven 7: seven 7: seven ``` 注意,使用 `ListIterator` 增加和删除元素时需要先调用 `next` 方法来获取下一个元素,然后再调用 `add` 或 `remove` 方法。同时,使用 `ListIterator` 时必须使用 `List` 的实现类,例如 `ArrayList` 或 `LinkedList`,因为 `List` 接口并没有定义 `listIterator` 方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值