Help us understand the problem. What is going on with this article?

STL:vectorの要素アクセス方法 at と operator[]

STL のvectorを使っていて頭に入れておくべきことがあったので、ここにメモしておきます。
std::vectorの n 番目の要素の参照を返す(要素へアクセスする)方法は大きく2つあります。
さあ、あなたはどっち?
iteratorを使ったアクセスについてはまた改めて!

vector::at

境界チェックをする(vectorの管理範囲外にアクセスしていないか)
  範囲外アクセスをした時、std::out_of_rangeの例外を送出する。
  範囲外アクセスチェックのため、若干の OH(オーバーヘッド)が生じる。

例.
// vectorにある要素の値を変数に代入したり
variable = vector.at(index);

// ある値をvectorにある要素に代入したり
vector.at(index) = value;

vector::operator[]

境界チェックをしない
  範囲外アクセスをした時、 未定義動作を行う。
  範囲外アクセスチェックをしないため、OH が生じない。

例.
// vectorにある要素の値を変数に代入したり
variable = vector[index];

// ある値をvectorにある要素に代入したり
vector[index] = value;

サンプルコード

「え?どゆこと?」
そう思ったあなた、是非ご自身の環境で以下のコードを試してみて下さい。
あ、for 文のindexに注意して下さいね。

sample.cpp
#include <iostream>
#include <vector>
#include <stdexcept>

int main()
{
    std::vector<int> sampleVector;

    // sampleVectorのindex0~9に要素を詰める. 
    for (int i = 0; i < 10; i++)
    {
        sampleVector.push_back(i);
    }

    std::cout << "###std::vector::at" << std::endl;

    // at
    try
    {
        // sampleVectorの管理範囲外であるindex10の要素にアクセスする. 
        for (int i = 1; i <= 10; i++)
        {
            std::cout << sampleVector.at(i) << std::endl;
        }

        // atの境界チェックで例外を投げるため、この処理は実行されない. 
        std::cout << "Complete..." << std::endl;
    }
    catch (std::out_of_range& sampleException)
    {
        std::cout << "out of range!" << std::endl;
        std::cout << "Error : " << sampleException.what() << std::endl;
    }

    std::cout << std::endl << "###std::vector::operator[]" << std::endl;

    // operator[]
    try
    {
        // sampleVectorの管理範囲外であるindex10の要素にアクセスする. 
        for (int i = 1; i <= 10; i++)
        {
            std::cout << sampleVector[i] << std::endl;
        }

        // 境界チェック無しのため、そのまま不定値が出力され、実行完了となる. 
        std::cout << "Complete..." << std::endl;
    }
    // 境界チェック無しのため、例外は投げない. 
    catch (std::out_of_range& sampleException)
    {
        std::cout << "out of range!" << std::endl;
        std::cout << "Error : " << sampleException.what() << std::endl;
    }

    std::cout << "End..." << std::endl;

    return 0;
}
出力.
###std::vector::at
1
2
3
4
5
6
7
8
9
out of range!
Error : invalid vector subscript

###std::vector::operator[]
1
2
3
4
5
6
7
8
9
2011707104
Complete...
End...

おやおや、全然違う結果になっていますねぇ
へっへっへ・・・
std::vector::operator[]の方は、なんだかとんでもない値を出力していますねぇ
へっへっへ・・・

まとめ

上記2つの違いは「範囲外アクセスをした時に、未定義動作を行うか例外を投げるか」です。
防御的プログラミングということであれば、未定義動作を行わないことが保証されている方をできるだけ使うべきだと思います。

atは範囲外アクセスに対してstd::out_of_range例外を投げるため、適切に処理されなかった場合、std::terminateが呼ばれてプログラムが異常終了します。
例外処理を用意していなかったとしても、プログラムが終了するだけです。
デバッグも比較的容易でしょう。

未定義動作を原因とするバグは、実際に未定義動作を行った箇所と異なる箇所で致命的なエラーを発生させることも多くあります。
エラー発生箇所と原因箇所が異なる場合、デバッグは困難になるでしょう。

個人的にはまずatを使うことをオススメしたいかなぁ。

at派 vs operator[]派の議論を見たいので、よかったらコメント下さい!

Chomolungma
FB大歓迎!! オネシャス!! ブログ https://chomolungma-kumamon.hatenablog.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした