terminate called after throwing an instance of 'std::out_of_range' の原因と直し方
std::vectorの範囲外の要素に .at() でアクセスしたときに、例外std::out_of_rangeが投げられ、それを捕まえずにプログラムが終了してしまうバグです。
エラーメッセージの読み方
terminate called after throwing an instance of 'std::out_of_range'
terminate called after throwing an instance of 'std::out_of_range'- ランタイム(または例外機構、assert)が不整合を検知して出したメッセージ
Aborted- この後プロセスは強制終了します(Aborted)
このエラーが出る典型パターン
パターン1
1 #include <iostream> 2 #include <vector> 3 int main() { 4 std::vector<int> nums = {1, 2, 3}; 5 std::cout << nums.at(10) << std::endl; ^ 6 return 0; 7 }
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 10) >= this->size() (which is 3)
Aborted
.at()は範囲外アクセスを検知するとstd::out_of_range例外を投げます。それを捕まえるtry-catchが無いとプログラム全体がterminateで強制終了します。
直し方: 10 を 1 にします。
広告
広告スロット(未設定)
パターン2
1 #include <iostream> 2 #include <vector> 3 int main() { 4 std::vector<int> scores = {70, 80, 90}; 5 std::cout << scores.at(5) << std::endl; ^ 6 return 0; 7 }
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 5) >= this->size() (which is 3)
Aborted
要素数3のvectorに対して添字5でアクセスすると、5は0〜2の有効範囲を超えているためstd::out_of_rangeが投げられます。
直し方: 5 を 2 にします。
パターン3
1 #include <iostream> 2 #include <vector> 3 int main() { 4 std::vector<int> items = {5, 10}; 5 std::cout << items.at(7 ) << std::endl; ^ 6 return 0; 7 }
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 7) >= this->size() (which is 2)
Aborted
operator[]と違い、.at()は範囲チェックのコストと引き換えに安全な例外を保証します。捕まえずに使うと未捕捉例外でプロセスが落ちます。
直し方: 7 を 0 にします。
よくある誤解
「vectorの添字アクセスはいつでも安全にチェックされる」というのは誤解です。角括弧の operator[] は範囲チェックをせず、範囲外でも黙って未定義動作になります。範囲チェック付きでアクセスしたいときに使うのが .at() で、その代わり例外が飛んできます。
まとめ
terminate called after throwing an instance of 'std::out_of_range'は中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。