map的[]运算符在用法上和我们对[]常规理解大有出入,因此也往往很容易造成了使用上的失误,在这点上我强烈认为stl设计犯了大错。
首先看其函数声明:
T& operator[] ( const key_type& x ); 在 http://www./reference/stl/map/operator[].html 的描述中,该声明等效于: (*((this->insert(make_pair(x,T()))).first)).second 倏忽的程序员一不留意就会栽入陷阱,因为在我们的常规理解里,[]操作不应该对本不属于容器自己的关键字做查询操作。但 map却直接执行了一次insert操作。 看以下代码: #include <iostream>#include <map>using namespace std;class MapManager{public : typedef map<string, string> MapNameToID; string ret(const string& name) { return m_map[name]; } void list() { for ( MapNameToID::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) { cout << "(" << iter->first << ", " << iter->second << ")" << endl; } }private : MapNameToID m_map;};int main(){ MapManager m; cout << m.ret("yao") << endl; cout << m.ret("jian") << endl; m.list(); return 0;} 类MapManager的设计者本来希望通过ret(int index)查找关键字的值,但显然设计者这么做实际上不小心给map加入了新元素当然,疏忽的地方在于,对于查询函数,应该加上const保护类成员,这样至少会编译错误。也就是说,压根在这里就不该 使用[]重载,而是应该用find,当然,如果find之前没有先判断该key是否存在,那么查询不存在的key将导致运行时错误。 或许[]重载正是为了保护查询不存的key时,不会出现运行时错误而选择了insert操作,但这样似乎也不是好办法。 正确写法: #include <iostream>#include <map>using namespace std;class MapManager{public : typedef map<string, string> MapNameToID; string ret(const string& name) const // 加const { MapNameToID::const_iterator iterRs = m_map.find(name); if (m_map.end() != iterRs) { return iterRs->second; // 用find(name)->second; } else { return ""; } } void list() { for ( MapNameToID::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) { cout << "(" << iter->first << ", " << iter->second << ")" << endl; } }private : MapNameToID m_map;};int main(){ MapManager m; cout << m.ret("yao") << endl; cout << m.ret("jian") << endl; m.list(); return 0;} 另外,说说另一个用法: #include <iostream>#include <map>using namespace std;class K{public : K() { cout << "K()" << endl; } K(int) { cout << "K(int)" << endl; }};int main(){ map<int, K> mp; K k; mp[1] = K(3); //mp.insert(map<int, K>::value_type(1, K(3))); return 0;} 以上代码输出是:K() K() K(int) 而直接用被注释掉的insert的话输出是: K() K(int) 这里存在的效率差别我就不多说了。 总之,map的[]重载确实给我们带来了编码上感性上的便利,但总体而言,对于讲究效率和代码质量的程序员,似乎就不那么 推荐使用了。 |