STL container trick usage

vector<int> veci;

veci.push_back(1);
veci.push_back(2);
veci.push_back(3);
veci.push_back(3);
veci.push_back(4);
veci.push_back(5);
veci.push_back(3);
veci.push_back(2);
veci.push_back(3);

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); iter++)
{
if( *iter == 3)
veci.erase(iter);
}

MSDN上明确说明:

Iterators, pointers and references pointing toposition (orfirst) and beyond are invalidated, with all iterators, pointers and references to elements beforeposition (orfirst) are guaranteed to keep referring to the same elements they were referring to before the call.

用erase来删除某迭代器iterator所指向的元素,删除后,不仅该被删元素的迭代器iterator失效,而且指向被
删元素之后的所有迭代器都失效。那么像iter++这种对已经删除的元素的迭代器iter的操作是未知的,可能不同的编译器的行为不一样。那么删除掉一个元素后,我们一定不要再操作它。


查看MSDN,对于erase的返回值是这样描述的:An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end  if the operation erased the last element in the sequence.,于是改代码:

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); iter++)
{
if( *iter == 3)
iter = veci.erase(iter);
}

这段代码有两个错误的:

1)无法删除两个连续的"3"(删除第一个"3"后,iter指向它紧邻的第二个"3",再for循环时,iter++则指向了第二个"3"的下一个元素“4”,顾第二个"3"没有删掉。);

2)当3位于vector最后位置的时候,也会出错(iter++就是在veci.end()上执行++操作)


正确的代码应该为:

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); )
{
if( *iter == 3)
iter = veci.erase(iter);
else
iter ++ ;
}

或者:

veci.erase(remove(veci.begin(), veci.end(), 3),  veci.end());


vector是一个顺序容器(list、deque),erase后,后面的元素自动前移。而且erase后,参数iter不再有效,因素不能直接对iter进行操作。

对vector进行erase操作正确的方法是使用erase方法的返回值。erase返回最后一个被删除元素的下一个元素。


而map非等顺序容器则不同,用红黑树实现的,删除一个元素后,其它所有的元素都还是有效的。除了使用上述vector的方法外,还可以利用c++的后置++的技巧进行erase操作。
方法如下:

    for (MAP::iterator it = theMap.begin(); theMap.end()!=it;)
    {
  if (canDel(*it))
    {
     //it会先赋值给erase的形参,然后在erase执行之前自己加一。所以it加一的时候it还没有被删除,是有效的,可以正确地得到它的下一个元素。

  theMap.erase(it++);
  }
    else
    {
    ++it;
  }


vector中的erase方法效率是很低的,因为为了保持vector中元素在内存空间中的连续性,在删除某个元素之后,需要将其后的元素依次向前移动一个位置,平均复杂度为on)。

gcc erase的实现如下:

iterator erase(iterator position)
{
if (position + 1 != end())
copy(position + 1, finish, position); //
后续元素往前移动
--finish;
destroy(finish);

}

二 Map 根据key默认构造pair

data_type&  

operator[](const key_type& k)  

Returns a reference to the object that is associated with a particular key.If the map does not already contain   such an object, operator[] inserts the default object data_type(). 

[3]Since operator[] might insert a new element into the map,it can 't possibly be a const member function.Note   that the definition of operator[]is extremely simple:m[k]is equivalent to (*((m.insert(value_type(k,data_type()))).first)).second.Strictly speaking,this member function is unnecessary:it exists only for convenience.

 

map <int,string>m;

cout < <m[1] < <endl;    

m[1]在这里被创建了,如果不创建,那它该显示那个string对象呢?或者返回一个非法的string对象?用异常来通知调用者m[1]不存在?   这对会带来复杂度,而且可能还是错误的

map <int,string>  m2;

m2[5]= "5 ";  其实这里m[2]  string对象就是先被默认构造出来的

 

其实这里赋值的时候,首先是执行m2[5]key5pair不存在,就默认构造一个key5pair对象并插入之。然后通过=号设置pairvalue5.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值