【C++】コンテナの要素アクセス: .at() と [] の違いと使い分け

目次

はじめに

C++のstd::vectorstd::mapといったコンテナに格納された要素にアクセスする際、よく似た2つの方法があります。

  1. 添字演算子 []: my_vector[5]my_map["key"] のように、角括弧でアクセスする方法。
  2. .at() メンバ関数: my_vector.at(5)my_map.at("key") のように、メンバ関数でアクセスする方法。

普段は何気なく [] を使っている方も多いかもしれませんが、この2つの方法には、指定した要素が存在しなかった場合の動作に、プログラムの安全性を左右する重要な違いがあります。

この記事では、.at()[] の違いと、それぞれの適切な使い分けについて解説します。


.at()[] のサンプルコード

このコードは、std::map に対して、存在するキーと存在しないキーの両方で、.at()[] を使ってアクセスを試みます。

完成コード

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <stdexcept> // out_of_range

using namespace std;

int main() {
    map<string, int> stock = {{"apple", 10}, {"orange", 18}};

    // --- 1. .at(): 安全なアクセス(範囲外チェックあり) ---
    cout << "--- .at()のテスト ---" << endl;
    try {
        // 存在するキーへのアクセス
        cout << "appleの在庫: " << stock.at("apple") << endl;
        
        // 存在しないキー("grape")へのアクセス
        cout << "grapeの在庫: " << stock.at("grape") << endl; // この行で例外が発生
    }
    catch (const out_of_range& e) {
        cout << "エラー: " << e.what() << endl;
    }

    cout << "\n--- 2. []: 高速なアクセス(範囲外チェックなし) ---" << endl;
    // 存在するキーへのアクセス
    cout << "orangeの在庫: " << stock["orange"] << endl;
    
    // 存在しないキー("banana")へのアクセス
    // -> mapに "banana":0 という新しい要素が自動で追加される!
    cout << "bananaの在庫: " << stock["banana"] << endl;
    
    cout << "\n--- 最終的なmapの状態 ---" << endl;
    for (const auto& [key, value] : stock) {
        cout << key << ": " << value << endl;
    }

    return 0;
}

コードの解説

1. .at() メンバ関数

  • 動作: 指定されたキー(またはインデックス)が存在するかを必ずチェックします。
  • 存在しない場合: std::out_of_range という例外を投げます。プログラムはクラッシュしませんが、try-catch ブロックでこの例外を適切に処理する必要があります。
  • 使いどころ:
    • アクセスしようとしているキーが存在するか不確実な場合。
    • 範囲外アクセスを致命的なエラーとして、安全に処理したい場合。

2. 添字演算子 []

  • 動作: 範囲外チェックを行いません
  • 存在しない場合 (map): std::map[] 演算子は、もし指定したキーが存在しなければ、そのキーと値初期化された値intなら0)を持つ新しい要素を、その場に自動で追加してしまいます。
  • 存在しない場合 (vector): std::vector[] 演算子は、もし範囲外のインデックスにアクセスすると、チェックを行わないため、未定義の動作(プログラムのクラッシュなど)を引き起こします。非常に危険です。
  • 使いどころ:
    • アクセスするキーが確実に存在すると分かっている場合。.at()よりもわずかに高速です。
    • mapで、キーが存在しなければ新しい要素を追加したい、という意図がある場合。

まとめ

.at()[]
範囲外チェックありなし
存在しない要素へのアクセス例外 (out_of_range) を投げるmap: 新要素を追加<br>vector: 未定義動作(危険!)
パフォーマンスわずかに遅いわずかに速い
推奨される使い方安全な読み取り存在が確実な要素の読み書き<br>(mapでの要素追加)

結論として、プログラムの安全性を最優先するならば、常に .at() を使うのが良い習慣です。 [] 演算子の挙動は便利ですが、特に vector での範囲外アクセスは深刻なバグの原因となるため、そのリスクを十分に理解した上で使いましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次