慎用C++ std::map 的[]运算符

原创 2008年09月18日 13:48:00
map的[]运算符在用法上和我们对[]常规理解大有出入,因此也往往很容易造成了使用上的失误,在这点上我强烈认为stl设计犯了大错。
首先看其函数声明:
T& operator[] ( const key_type& x );
http://www.cplusplus.com/reference/stl/map/operator[].html 的描述中,该声明等效于:
(*((this->insert(make_pair(x,T()))).first)).second
倏忽的程序员一不留意就会栽入陷阱,因为在我们的常规理解里,[]操作不应该对本不属于容器自己的关键字做查询操作。但
map却直接执行了一次insert操作。
看以下代码:
  1. #include <iostream>
  2. #include <map>
  3. using namespace std;
  4. class MapManager
  5. {
  6. public :
  7.     typedef map<string, string> MapNameToID;
  8.     string ret(const string& name)
  9.     {
  10.         return m_map[name];
  11.     }
  12.     void list()
  13.     {
  14.         for (   MapNameToID::iterator iter = m_map.begin();
  15.                 iter != m_map.end();
  16.                 ++iter)
  17.         {
  18.             cout << "(" << iter->first << ", " << iter->second << ")" << endl;
  19.         }
  20.     }
  21. private :
  22.     MapNameToID m_map;
  23. };
  24. int main()
  25. {
  26.     MapManager m;
  27.     cout << m.ret("yao") << endl;
  28.     cout << m.ret("jian") << endl;
  29.     m.list();
  30.     return 0;
  31. }
类MapManager的设计者本来希望通过ret(int index)查找关键字的值,但显然设计者这么做实际上不小心给map加入了新元素
当然,疏忽的地方在于,对于查询函数,应该加上const保护类成员,这样至少会编译错误。也就是说,压根在这里就不该
使用[]重载,而是应该用find,当然,如果find之前没有先判断该key是否存在,那么查询不存在的key将导致运行时错误。
或许[]重载正是为了保护查询不存的key时,不会出现运行时错误而选择了insert操作,但这样似乎也不是好办法。
正确写法:
  1. #include <iostream>
  2. #include <map>
  3. using namespace std;
  4. class MapManager
  5. {
  6. public :
  7.     typedef map<string, string> MapNameToID;
  8.     string ret(const string& name) const // 加const
  9.     {
  10.         MapNameToID::const_iterator iterRs = m_map.find(name);
  11.         if (m_map.end() != iterRs)
  12.         {   
  13.             return iterRs->second; // 用find(name)->second;
  14.         }
  15.         else
  16.         {   
  17.             return "";
  18.         }
  19.     }
  20.     void list()
  21.     {
  22.         for (   MapNameToID::iterator iter = m_map.begin();
  23.                 iter != m_map.end();
  24.                 ++iter)
  25.         {
  26.             cout << "(" << iter->first << ", " << iter->second << ")" << endl;
  27.         }
  28.     }
  29. private :
  30.     MapNameToID m_map;
  31. };
  32. int main()
  33. {
  34.     MapManager m;
  35.     cout << m.ret("yao") << endl;
  36.     cout << m.ret("jian") << endl;
  37.     m.list();
  38.     return 0;
  39. }


另外,说说另一个用法:


  1. #include <iostream>
  2. #include <map>
  3. using namespace std;
  4. class K
  5. {
  6. public :
  7.     K()
  8.     {
  9.         cout << "K()" << endl;
  10.     }
  11.     K(int)
  12.     {
  13.         cout << "K(int)" << endl;
  14.     }
  15. };
  16. int main()
  17. {
  18.     map<int, K> mp;
  19.     K k;
  20.     mp[1] = K(3);
  21.     //mp.insert(map<int, K>::value_type(1, K(3)));
  22.     return 0;
  23. }
以上代码输出是:
K()
K()
K(int)
而直接用被注释掉的insert的话输出是:
K()
K(int)

这里存在的效率差别我就不多说了。
总之,map的[]重载确实给我们带来了编码上感性上的便利,但总体而言,对于讲究效率和代码质量的程序员,似乎就不那么
推荐使用了。
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

std::map源码分析

默认构造的时候 初始化: void _Init() { // create head/nil node and make tree empty _Myhead = _Buynode(); ...

入门计划->学用stl std::map<std::string, int>

C++:一种比较流行的强大功能面向对象编程语言,应用和前景都很广阔。stl:C++标准模板库,功能极其强大,将其完全掌握后C++编程会相当容易。map:一种关系式容器,可以根据关键字匹配多种数据。st...
  • awzzz
  • awzzz
  • 2003-08-27 20:57
  • 6686

std::map用法

映射和多重映射基于某一类型Key的键集的存在,提供对T类型的数据进行快速和高效的检索。对map而言,键只是指存储在容器中的某一成员。Map不支持副本键,multimap支持副本键。Map和multim...

std::map用法

std::map用法    STL是标准C++系统的一组模板类,使用STL模板类最大的好处就是在各种C++编译器上都通用。    在STL模板类中,用于线性数据存储管理的类主要有vec...

C++ std::map按值查找

我们都熟知STL 中模板库的std::map可以按key查找,但是有时候应用中会出现Value 也是唯一的,不如GUID等,那么如何按Value来进行查找呢?

【c++】映射表std::map

文章内容为网络搜集内容std::map映射表(Map)容器是一个按特定顺序存储以键值对组合而成的元素的关联容器// template < class Key, class T, cl...

[C++/object c]_[初级]_[std::map容器的使用总结和NSDictionary词典使用总结]

map容器 场景:map的元素是一对对的“关键字―值”组合,“关键字”用于搜寻,而“值”用来表示我们要存取的数据。 在map容器中,每个关键字只能出现一次,不能重复 void TestMap() { ...

[C/C++标准库]_[初级]_[std::map的使用细节]

map 1.判断key是否存在的注意细节. 以前是通过[key]的返回值来判断key是否存在,这样是不行,因为map会创建不存在key的相应的pair.正确的方法是通过find来判断. #in...

子线程中慎用CString, std::string

今天CODING时遇到了内存泄露问题,发现原因在子线程中,当程序退出的时候,子线程被强行退出(非正常退出),导致内存泄露.于是开始调试,寻找,却没发现自己子线程中有任何的new或者malloc了,郁闷...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)