mapのoperator[]の罠
mapを使ったあるプログラムを書いていて、やたらとメモリを食うので、何だろうといろいろ試行錯誤しながら調べてみたら、どうもmapの使い方に問題があるのではないかということが分かってきた。
mapのリファレンスを探して読んでみると、以下のようなことが書いてある。
https://cpprefjp.github.io/reference/map/map/op_at.html
戻り値
キーxに対応する値を返す。対応する要素が存在しない場合は、要素をデフォルト構築して参照を返す。
「デフォルト構築」ってなんぞや?・・・
そこで、(いろいろすっ飛ばして)検証プログラムを書いてみた。
#include <iostream> #include <map> using namespace std; int main(int argc, char** argv) { map<int, int*> m; int a = 1; int b = 2; // (1) { map<int, int*>::iterator it = m.find(1); cout << "(1) " << (it == m.end()) << endl; } // (2) { int* p = m[1]; cout << "(2) " << (p == NULL) << endl; } // (3) { map<int, int*>::iterator it = m.find(1); cout << "(3) " << (it == m.end()) << ":" << (it->second == NULL) << endl; } // (4) { m[1] = &a; map<int, int*>::iterator it = m.find(1); cout << "(4) " << (it == m.end()) << ":" << (it->second == NULL) << ":" << (it->second == &a) << endl; } return EXIT_SUCCESS; }
出力は以下のようになる。
(1) 1 (2) 1 (3) 0:1 (4) 0:0:1
(1)ではit
がm.end()
に等しいのに、(2)でm[1]
をやった後に(3)でもう一度find
を使うと、今度はm.end()
と等しくならなくなっている、つまり、mapの中に何かしらのエントリが存在する状態になっているようだ。
(4)はついでだが、m[1]
に何かを代入すると、当然ながらその値がmapに入ることになる。
これは罠だなぁ‥覚えておこう‥