map

未だに C++ の map の使い方がよくわからんという話。例えば int 型の ID の出現回数を map histogram とかで勘定する場合って

 map<int, int>::iterator found = histogram.find(id);
 if (found == histogram.end()) {
   histogram[id] = 1;
 }
 else {
   found->second++;
 }

とか書く人はまぁ Ruby とかそのへん使っとけってことでいいのかなと思うんですが(以下 O(2log(N)) は論外ということで)、

 pair<map<int, int>::iterator, bool> p = histogram.insert(make_pair(id, 1));
 if (!p.second) {
   p.first->second++;
 }

こんな感じでいいんかしら。いやこのケースだと 0 初期化でいいから単に histogram[id]++; でいいんだよな。

ええと… vector*> とかしたい時とかかなぁ。 int key => int value で key に対して value が複数ある場合。 multimap もなんかイヤなケースだとしてください。

 map<int, vector<int>*> hoge;
 pair<map<int, vector<int>*>::iterator, bool> p =
     hoge.insert(make_pair(key, 0));
 if (p.second) {
   p.first->second = new vector<int>;
 }
 (*p.first->second)->push_back(value);

ダサいですねこれは。でもこれ以上マシな書き方あるんでしょうか。あるいは

 map<int, vector<int>*> hoge;
 vector<int, vector<int>*>::iterator found = hoge.find(key);
 if (found == hoge.end()) {
   found = hoge.insert(found, make_pair(key, new vector<int>));
 }
 (*found->second)->push_back(value);

このへんとか?これなんかキモくて好きくないんだけど。特にヒント付き insert って計算量的にいいのはわかるけど、普通に比較一回は多くなるんじゃないのかなーとか。

なんか Effective STL とか見てると value がなんか重い型の場合について考えてるんだけど、まぁ普通に考えて C++ で重い型とか少なくとも人と一緒に書く場合はポインタにするよなぁとか思うわけでして。でこう、 value がポインタの場合のベストプラクティスって未だによくわからんのですよね。

あるいはこのへんが正解なの?なんか C++ 的にはダサげな気がするけど。

 map<int, vector<int>*> hoge;
 vector<int>** found = &hoge[key];
 if (!*found) {
   *found = new vector<int>;
 }
 (*found)->push_back(value);

TODO: とりあえず上記を全部コンパイル通してみる

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h