STL のmap
を使っていて頭に入れておくべきことがあったので、ここにメモしておきます。
std::map
の指定キーに対応する要素の参照を返す(要素へアクセスする)方法は大きく2つあります。
さあ、あなたはどっち?
map::at
1.存在しないキーを指定すると、std::out_of_range
の例外を送出する
2.const
なmap
にもアクセスできる
map
をメンバ変数としていて、const
メンバ関数の中でmap
の要素にアクセスする時に使える。
※const
参照渡しでも同様
例.
// mapにある要素の値を変数に代入したり
variable = map.at(key);
// ある値をmapにある要素に代入したり
map.at(key) = value;
// constなmap2を生成する
const std::map<key, value> map2(map);
// map2にある要素の値を変数に代入できる
variable = map2.at(key);
map::operator[]
1.存在しないキーを指定すると、自動でデフォルト値の要素が追加され、その参照を返す
2.const
なmap
にはアクセスできない
例.
// mapにある要素の値を変数に代入したり
variable = map[Key];
// ある値をmapにある要素に代入したり
vector[Key] = value;
// constなmap2を生成する
const std::map<key, value> map2(map);
// コンパイルエラー
variable = map2[key];
サンプルコード
「え?どゆこと?」
そう思ったあなた、是非ご自身の環境で以下のコードを試してみて下さい。
sample.cpp
# include <iostream>
# include <map>
# include <stdexcept>
int main()
{
// キー:文字列、値:intとしたmapを生成する.
std::map<std::string, int> sampleMap;
// sampleMapに"John"をキーとした要素を詰める.
sampleMap.insert(std::make_pair("John", 5));
// sampleMapに"Ken"をキーとした要素を詰める.
sampleMap["Ken"] = 10;
std::cout << "###std::map::at" << std::endl;
// at
try
{
std::cout << sampleMap.at("John") << std::endl;
std::cout << sampleMap.at("Ken") << std::endl;
std::cout << sampleMap.at("Tom") << std::endl;
// キーチェック時に例外を投げるため、この処理は実行されない.
std::cout << "Complete..." << std::endl;
}
catch (std::out_of_range& sampleException)
{
std::cout << "can't find the key!" << std::endl;
std::cout << "Error : " << sampleException.what() << std::endl;
}
std::cout << std::endl << "###std::map::operator[]" << std::endl;
// operator[]
try
{
std::cout << sampleMap["John"] << std::endl;
std::cout << sampleMap["Ken"] << std::endl;
std::cout << sampleMap["Tom"] << std::endl;
// キーチェック時に例外を投げず、自動追加されるデフォルト値が出力され、実行完了となる.
std::cout << "Complete..." << std::endl;
}
// キーチェック時に例外は投げない.
catch (std::out_of_range& sampleException)
{
std::cout << "can't find the key!" << std::endl;
std::cout << "Error : " << sampleException.what() << std::endl;
}
std::cout << "End..." << std::endl;
return 0;
}
出力.
### std::map::at
5
10
can't find the key!
Error : invalid map<K, T> key
### std::map::operator[]
5
10
0
Complete...
End...
あ、int
だとデフォルト値は0なのね。
まとめ
vector
とは異なり、存在しないキーに対応する要素へアクセスを、上記2つのどちらで行っても、未定義処理が行われることはありません。
若干用途が異なるので、どちらを使うかはケースバイケースでしょうかね。