1、怪异的现象
一次偶然的误用,竟然发现map中删除的元素,在后面又出现在了map中,如下代码所示
map<int, A*> containers;
A* a1 = new A();
A* a2 = new A(2);
A* a3 = new A(3);
containers.insert(pair<int, A*>(1,a1));
containers.insert(pair<int, A*>(2,a2));
containers.insert(pair<int, A*>(3,a3));
cout << "containers.size()=" << containers.size() << endl;
// remove 2 from map
containers.erase(2);
cout << "---------------------------After erase--------------------------" << endl;
cout << "containers.size()=" << containers.size() << endl;
for (auto& m : containers) {
cout << m.first << ":" << m.second->getB() << endl;
}
delete a1;
a1 = nullptr;
delete a2;
a2 = nullptr;
delete a3;
a3 = nullptr;
// []重载
if (containers[2] == nullptr) {
cout << "containers[2] is null" << endl;
} else {
cout << "containers[2] not null" << endl;
}
cout << "---------------------------After if--------------------------" << endl;
cout << "containers.size()=" << containers.size() << endl;
功能很简单,就是从map中删除key为2的元素,释放完资源后判断了一下key为2的元素是否为nullptr,结果神奇的现象出现了,就是这里的判断导致map的大小又回到了删除前的大小。
看到这里 ,你是不是也一脸问号,明明删除了一个元素之后,map的大小为何又增加了?
2、错误使用map []运算符
还记得上面代码最后的if判断吗,罪魁祸首就是这个判断
这里本意是使用key去看map中对应的value值是否为空,结果却重新在map中添加了一个元素。这个地方当时和同事排查了两三天,gdb一步步调试,看到gdb显示的map大小从2变为3的时候,我们都懵了。压根没想到是map []
运算符的问题,在错误的方向上找了很久…最后还是同事调试的时候跟进去了map的源码中,终于发现了罪魁祸首!!!下面的内容截自stl_map.h
:
map中保存的value是指针类型,默认初始值是nullptr,就导致if判断中又把删除的元素加进去了。
注意!!!这里如果要判断key为某个值的元素是否存在,一定不能在删除之后使用[],可以使用count(key)去判断
改为下面的判断就没有问题了
if (containers.count(2) > 0) {
cout << "containers[2] exist" << endl;
} else {
cout << "containers[2] not exist" << endl;
}
3、总结
C++的STL很强大,需要注意的细节也有很多,就像这次不了解map的[]运算符会重新生成一个元素,导致走了很多冤枉路。特别在此记录,分享给更多的人,少踩坑!
4、附录-测试代码
A.h
#ifndef A_H
#define A_H
class A{
public:
A();
A(int _x);
int getB();
private:
int b{-1};
};
#endif //A_H
A.cpp
#include "A.h"
A::A() {
}
A::A(int _x) {
b = _x;
}
int A::getB() {
return b;
}
main.cpp
#include <iostream>
#include <map>
#include "A.h"
using namespace std;
int main(int argc, char *argv[])
{
map<int, A*> containers;
A* a1 = new A();
A* a2 = new A(2);
A* a3 = new A(3);
containers.insert(pair<int, A*>(1,a1));
containers.insert(pair<int, A*>(2,a2));
containers.insert(pair<int, A*>(3,a3));
cout << "containers.size()=" << containers.size() << endl;
// remove 2 from map
containers.erase(2);
cout << "---------------------------After erase--------------------------" << endl;
cout << "containers.size()=" << containers.size() << endl;
for (auto& m : containers) {
cout << m.first << ":" << m.second->getB() << endl;
}
delete a1;
a1 = nullptr;
delete a2;
a2 = nullptr;
delete a3;
a3 = nullptr;
// []重载会生成不存在的key-value,在删除之后不能使用这种方式判断
// if (containers[2] == nullptr) {
// cout << "containers[2] is null" << endl;
// } else {
// cout << "containers[2] not null" << endl;
// }
// count判断是否存在,ok
if (containers.count(2) > 0) {
cout << "containers[2] exist" << endl;
} else {
cout << "containers[2] not exist" << endl;
}
cout << "---------------------------After if--------------------------" << endl;
cout << "containers.size()=" << containers.size() << endl;
return 0;
}