以vector的遍历形式遍历map操作数据误区&&map中的[]运算符原理!

博客讨论了STL中map的operator[]与find方法的不同,指出operator[]在键值不存在时会插入默认值,而find只会返回迭代器。作者提醒,直接使用operator[]可能导致意外的元素插入,特别是在未检查是否存在键值的情况下。推荐使用find配合迭代器进行安全的查找操作。此外,文章还提到了通过operator[]插入元素时的遍历方式可能带来的空间浪费和性能损耗。

    std::map不是顺序容器,这应该都知道的,map中重载了operator []操作符,可以用map的键值索引到相关的数据,但是这个[]和一般数组的[]可不一样。有的人又认为既然[]就是利用下标做索引和std::map中的find用键值索引是不是一样的,所以有的会写出下面类似的代码:

std::map<int,int*> mapTemp;

...

int* Find1(int i)

{

    if( mapTemp.end() == mapTemp.find(i) )

        return NULL;

    return mapTemp[i].second;

}

上面代码有什么问题?

看看operator []的源码,operator []返回的是Value的类型:

mapped_type& operator[](const key_type& _Keyval)
  { // find element matching _Keyval or insert with default mapped
  iterator _Where = this->lower_bound(_Keyval);
  if (_Where == this->end()
   || this->comp(_Keyval, this->_Key(_Where._Mynode())))
   _Where = this->insert(_Where,
    value_type(_Keyval, mapped_type()));
  return ((*_Where).second);
  }

再看看find的源码,find返回的是一个常量迭代器:

const_iterator find(const key_type& _Keyval) const
  { // find an element in nonmutable sequence that matches _Keyval
  const_iterator _Where = lower_bound(_Keyval);
  return (_Where == end()
   || _DEBUG_LT_PRED(this->comp,
    _Keyval, _Key(_Where._Mynode()))
     ? end() : _Where);
  }

对比上面黑色加粗的部分应该知道了吧,就是Find1中你重复找了两遍,标准的写法应该是

int* Find2(int i)

{

    std::map<int,int*>::iterator iter = mapTemp.find(i);

    if( mapTemp.end() != iter )

        return iter->second;

    return NULL;

}

其实Find1还好,就是多查了一遍,至少还判了索引的有效值,如果写成下面这样

int* Find3(int i)

{

    return mapTemp[i].second;

}

那就悲剧了,再看看operator []的源码红色加粗的部分,[]操作符再没有找到该键值索引值的时候会插入一个键值索引为i的东西。可以发现不存在的key在被索引后被添加到了map中并被赋予了一个默认值(一般的,整数为0,字符,字符串为空,指针为空)这东西要是不了解bug查起来肯定会比较头痛的。

记录警示之!!!

QA:

Q. 为什么stl对于map要提供operator []运算符重载,并且不存在的key在被索引后被添加到了map中并被赋予了一个默认值?

        主要是便于插入。

Q. map类似以下遍历方式有什么问题?

	map<string, int*> mp;

	mp[1] = new int(1);
	mp[3] = new int(3);
	mp[5] = new int(4);
	mp[7] = new int(6);

	for (int i = 0; i < mp.size(); ++i) {
		cout << *mp[i] << endl;
		delete mp[i];
		mp[i] = nullptr;
	}

A. 1. 如果key值跨度比较大,mp的大小就是最大的key+1。①空间浪费 ②删除value性能损耗。

    2. 如果仅仅如此方式遍历使用数据,里面会有很多脏数据,大概率会影响后续逻辑,所以不建议如此遍历。

    operator []使用针对于明确key-value的情况;对于透明删除、透明使用都不适用,请切换遍历方式。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值