背景
项目中经常需要对std::map进行插入和取值操作,以前经常使用find和[]直接操作,c++11引入了at方法。
本文主要介绍它们的使用方法和不同之处。
find
很直观的查找元素操作,如:
#include <map>
#include <iostream>
using namespace std;
int main()
{
map<string, int> m;
m["xiaoming"] = 80;
m["xiaogang"] = 90;
m["xiaoqing"] = 100;
auto iter = m.find("xiaoqiang");
if (iter != m.end())
{
// 找到了
cout << "xiaoqiang's score: " << iter->second << endl;
}
else
{
// not found
cout << "not find xiaoqiang's score" << endl; // 应该输出该行
}
return 0;
}
它的特点:
- 有就是有,没有就是没有,需要判断find的返回结果,才知道有没有
[]
和数组的取值操作一样,使用中括号,由于使用简单(能少打几下键盘),很多人喜欢直接用。
但如果使用错误,调试bug的时候要多打一万倍的键盘([/捂脸])。
其实上个示例中已经使用了[]操作符,这里再扩展一下:
#include <map>
#include <iostream>
using namespace std;
int main()
{
map<string, int> m;
m["xiaoming"] = 80;
m["xiaogang"] = 90;
m["xiaoqing"] = 100;
cout << "xiaoqing's score: " << m["xiaoqing"] << endl; // 输出100
cout << "xiaoqiang's score" << m["xiaoqiang"] << endl; // 输出0
return 0;
}
看到了吧,[]操作符的特点:
- 不管有没有,都是有。因为没有就是0,字符串就是空。反正就是给它是初始值。
- 对于示例中给map插入值的操作,也是一样,如果原先不存在该key,则插入,如果存在,则覆盖插入。
at
c11引入的at方法,用于取值,但它是进行越界检测,这会损失效率。
如果存在,则返回它的值,如果不存在,则抛出异常。
#include <map>
#include <iostream>
using namespace std;
int main()
{
try
{
map<string, int> m;
m["xiaoming"] = 80;
m["xiaogang"] = 90;
m["xiaoqing"] = 100;
cout << "xiaoqing's score: " << m.at("xiaoqing") << endl; // 输出100
cout << "xiaoqiang's score" << m.at("xiaoqiang") << endl; // 抛出异常:out_of_range exception
}
catch(std::exception& e)
{
cout << "catch exception: " << e.what() << endl;
}
return 0;
}
可以看出,at的特点如下:
- 相比于find,能少敲键盘
- 相比于[],更安全
- 性能会有损失
- 所以常用于待查找的key都应该存在的情况,如果查找的key不存在,则说明程序有问题了
- 其实,我用at还有一个原因,那就是对于const的map,即使是取值,用[]操作符也是发生编译时错误,用at就没事了
小结
虽然都能达到取值的目的,但用法上的些微差别可能导致使用上的bug,所以一般性的建议如下:
- 如果纯粹是查找取值,不要用[]操作符,因为它会自动创建不存在的元素
- 正因为上面的原因,[]仅用于非const的情形下。在const map下使用[]会导致编译期错误
- 如果不确定待查找的值是否存在,且不存在也是合理的,则使用find,判断返回值是否是end()
- 如果待查找的值肯定存在,如果不存在就是逻辑上的错误,则使用at,处理out_of_range异常
另外,如果仅是判断元素是否存在,也可以使用count,因为map不存在重复的key,所以它的效率也可以。
它比使用find可以少打好几下键盘呢 [/可爱] !