vector::erase & map::erase (C++11)

  • Post author:
  • Post category:其他


前言

关于这两者的区别和用法,网络上有很多五花八门的答案,有的还有很多错误,十分容易误导初学者。这里结合StackOverflow上的专家回答以及C++标准库来做一个简单的总结。

vector 与 map的区别

我们知道,vector是连续存储的数据结构,本质上是一个数组(指针确定数组的属性,如迭代器的起始和末尾,vector的size以及capacity等)。map是一个红黑树的数据结构,关于这部分的具体内容可以查看相关的标准库。因此,树形结构的map不是连续存储的。

函数功能

这两个函数都是从目标容器中删除指定元素,我们这里只讨论形参为迭代器类型的对应函数实现。

具体区别

首先,map与vector的erase都会产生返回值(C++11标准,C++98的map无返回值)。由我们已经预设的前提(函数形参为迭代器类型),erase操作都会返回一个指向被删除元素的下一个元素的迭代器(或者end()迭代器)。区别在于,vector的erase会破坏原有的数据存储(被删除元素的右侧元素整体向前移动),而map的erase则不会破坏树的完整结构,只是删除当前结点的元素。迭代器的本质都是指针,vector和map的erase都会使当前元素对应的迭代器失效,区别在于,vector的整个迭代器都会失效,而map只有当前被删除的元素迭代器失效。原因我们上面已经提过,是map和vector的内部实现不同造成。此外,SGI的文档中对map操作有这样的一句描述:Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.

简单说,map的insert/erase操作都必须保证map的这样一个特性:这些操作不影响其它指向已存在元素的迭代器。

概念小结

首先,vector/map的erase操作都会使当前元素的迭代器失效,区别在于,vector会影响所有的存储元素,而map只会影响被删除的元素。

其次,扩展到连续存储容器(queue)以及关联容器(set),都具备类似的性质。

使用范式

vector::erase

     vector<int> iVec{1,3,3,4,5};
     auto it = iVec.begin();
     for(;it!=iVec.end();)
     {
         if(*it % 3 ==0)
             it=iVec.erase(it);    //删除元素,返回值指向已删除元素的下一个位置    
         else
             ++it;    //指向下一个位置
     }

注意到,我们在删除元素之后直接将返回值赋给it,这里绝对不能做自加操作,因为迭代器(后续)完全失效,这样的操作是未定义的。

map::erase

1.使用删除之前的迭代器定位下一个元素。
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
mapTest.erase(iter++); // 这是与之前代码不同的地方 
}

2. erase() 成员函数返回下一个元素的迭代器
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
iter=mapTest.erase(iter);
}

这里给出两种写法,但更推荐的是第二种,因为在形式上与vector的写法基本一致,此外,第一种写法的理解关系到后置自增运算符的实现(先复制,再自增,后返回复制值),这种操作保证了iter迭代的有效性,同时,也体现了map::erase不影响之后元素的性质,更加贴近原理。如果把自增操作放在for循环内部,则是未定义的操作,因为此时iter迭代器已失效(元素被删除,指针已失效,无法自增)。



版权声明:本文为feifeiiong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。