std::map に「挿入か更新をする」ときの idiom をすぐに忘れてしまうのでメモしておく.

std::map<S, T> mp;

と宣言されているとする.

1. 無条件で,s の値を t にする

通常は次で良い:

  mp[s] = t;

もともと s が有ったか無かったのかも知りたい場合や,s へのイタレータも欲しい場合には,次のようにする:

  auto [it, b] = mp.insert_or_assign(s, t);

b には,挿入が行われたかどうかが設定されるので,b が false なら,もともとキー s が存在していたことがわかる.it は s へのイタレータ.

2. キー s が無ければ,値を t にする.

次のように書くと,s の探索が2回走ってしまう.

  if (mp.find(s) == mp.end()) mp[s] = t;

次のようにすれば 1回ですむ.

  mp.emplace(s, t);

もともと s が有ったか無かったのかも知りたい場合や,s へのイタレータも欲しい場合には,次のようにする:

  auto [it, b] = mp.emplace(s, t);

b には,挿入が行われたかどうかが設定されるので,b が false なら,もともとキー s が存在していたことがわかる.it は s へのイタレータ.

3. キー s が無く,さらになんらかの条件も成り立てば,s の値を t にする.

次のように書くと,s の探索が2回走ってしまう.

  if (mp.find(s) == mp.end() and some_condition()) mp[s] = t;

次のようにすれば 1 回ですむ.

  auto it = mp.lower_bound(s);
  if ((it == mp.end() or it->first != s) and some_condition()) mp.emplace_hint(it, s, t);

lower_bound の戻り値を hint に使うのがポイント.(ChatGPTに教えてもらいました)