18_拡張for文(範囲for)とイテレータの基礎

はじめに

この章では、C++における「拡張for文(range-based for)」の使い方を学びます。配列やベクタのすべての要素に対して繰り返し処理を行うとき、より簡潔に記述できます。また、後半ではイテレータの概要にも触れます。

通常のfor文との比較

// 18_for_vs_range.cpp
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> nums = {10, 20, 30, 40};

    // 通常のfor文
    for (int i = 0; i < nums.size(); i++) {
        cout << nums[i] << " ";
    }
    cout << endl;

    // 拡張for文(範囲for)
    for (int n : nums) {
        cout << n << " ";
    }
    cout << endl;
    return 0;
}

基本構文とポイント

for (データ型 変数名 : コンテナ名) {
    // 処理
}
書き方 用途
for (int n : nums) 値のコピーで読み取り(元の値は変わらない)
for (const int& n : nums) 参照で読み取り専用(効率的・安全)
for (int& n : nums) 参照で値を変更したいとき
for (auto n : nums) 型推論(型を省略して書ける)
for (const int& n : nums) { ... } // 読み取り専用
for (int& n : nums) { ... }       // 値を変更したい場合

範囲forで値を書き換える

// 18_range_modify.cpp
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> nums = {1, 2, 3, 4, 5};

    for (int& n : nums) {
        n *= 2;  // すべて2倍
    }

    for (int n : nums) {
        cout << n << " ";
    }
    cout << endl;
    return 0;
}

補足:イテレータとは?

vectorlist のようなコンテナは、要素を順にたどるために「イテレータ」という仕組みを持っています。範囲for文の内部では、自動的にイテレータが使われています。

for (auto it = vec.begin(); it != vec.end(); ++it) {
    cout << *it << " ";
}

*it で要素、++it で次の要素へ進みます。C++のSTLでは頻繁に使われる概念です。

範囲for文はイテレータを内部で自動的に使っています。慣れてきたらイテレータを直接使う書き方も試してみましょう。

理解度チェック

問題18-1

次のコードは何を出力しますか?

vector<int> data = {3, 6, 9};
for (const int& d : data) {
    cout << d * 10 << " ";
}
解説を表示 正解:イ
各要素を10倍して表示しているだけで、元のベクタは変更されません。const int& は参照ですが変更は禁止されています。出力は "30 60 90 " です。

問題18-2

次のコードを実行した後、nums の内容はどうなりますか?

vector<int> nums = {1, 2, 3};
for (int n : nums) {
    n = n * 10;
}
for (int n : nums) cout << n << " ";
解説を表示 正解:ウ
for (int n : nums) は値のコピーです。n = n * 10 はコピー変数を変更するだけで、元の nums は変わりません。元の値を変更したい場合は for (int& n : nums) と参照にする必要があります。

問題18-3

次のコードを実行したとき、出力はどれですか?

vector<int> nums = {1, 2, 3};
for (int& n : nums) {
    n += 5;
}
for (int n : nums) cout << n << " ";
解説を表示 正解:ア
for (int& n : nums) は参照なので、元の要素を直接変更します。1+5=6、2+5=7、3+5=8 となり、出力は "6 7 8" です。

問題18-4

イテレータを使った次のコードと同等の範囲for文はどれですか?

for (auto it = vec.begin(); it != vec.end(); ++it) {
    cout << *it << " ";
}
解説を表示 正解:イ
範囲for文 for (auto n : vec) は内部でイテレータを使っており、vec.begin() から vec.end() まで順番に要素を取り出す処理と同等です。コードが簡潔になります。

コーディング演習

演習1:基本コードを動かす

18_01_range_for.cpp を作成し、次のコードを入力して実行しましょう。
// main.cpp
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> scores = {70, 80, 90, 60, 85};

    for (int s : scores) {
        cout << s << " ";
    }
    cout << endl;

    int total = 0;
    for (int s : scores) {
        total += s;
    }
    cout << "平均: " << (double)total / scores.size() << endl;
    return 0;
}

演習2:コードを改造する

18_01_RangeFormain.cpp をコピーして 18_02_RangeForMod に貼り付け、次の変更を加えてみましょう:

まとめ