HOWTO · C++

C++ で vector の内容を出力する方法

この記事では、C++ でベクターの内容を標準出力に出力する方法を紹介します。

このページの内容

C++ で vector の内容を出力する
std::vector のすべての要素を出力するには、要素を順に処理し、それぞれを std::cout に書き込みます。インデックス付きループ、範囲ベースのループ、std::copy、または std::for_each を使えます。範囲ベースのループ、auto、ラムダ式、初期化子リストの構文には C++11 以降が必要なため、例ではこの規格以降を使用します。

インデックス付きループで vector の要素を出力する

要素の値だけでなく位置も必要な場合は、インデックス付きループが便利です。範囲チェックを行いたい場合は at() を使います。範囲外の要素にアクセスすると、エラーが報告されます。operator[] は簡潔ですが、インデックスが有効であることを事前に確認する必要があり、この演算子自体は範囲をチェックしません。

次の例を実行します。

このセクションのコードと表示されるラベルや出力は英語のままです。

#include <iostream>
#include <cstddef>
#include <vector>

int main() {
    const std::vector<int> values{10, 20, 30};
    for (std::size_t i = 0; i < values.size(); ++i) {
        if (i != 0) std::cout << ' ';
        std::cout << values.at(i);
    }
    std::cout << '\n';
    for (std::size_t i = 0; i < values.size(); ++i) {
        if (i != 0) std::cout << ' ';
        std::cout << values[i];
    }
    std::cout << '\n';
}
10 20 30
10 20 30

ループ条件により、各インデックスは values.size() 未満に保たれます。vector が空の場合、ループ本体は一度も実行されないため、明示的に出力する改行だけが書き込まれます。

範囲ベースの for ループで vector の要素を出力する

範囲ベースのループでは、インデックスを管理せずに各要素を処理できます。値を const auto& として受け取るとコピーを避けられます。特に、要素が整数より大きな型の場合に便利です。

このセクションのコードと表示されるラベルや出力は英語のままです。

#include <iostream>
#include <string>
#include <vector>

int main() {
    const std::vector<std::string> names{"Ada", "Grace", "Linus"};
    bool first = true;
    for (const auto& name : names) {
        if (!first) std::cout << ' ';
        std::cout << name;
        first = false;
    }
    std::cout << '\n';
}
Ada Grace Linus

このループは値と値の間だけに空白を出力するため、末尾に区切り文字は付きません。vector が空なら値は出力されませんが、改行は出力されます。

std::copy で vector の要素を出力する

std::copy は、イテレーターで指定した範囲を出力イテレーターに渡します。アルゴリズムには <algorithm> を、std::ostream_iterator には <iterator> をインクルードします。2つ目のイテレーターは範囲の終端を示し、その要素が参照されることはありません。

このセクションのコードと表示されるラベルや出力は英語のままです。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main() {
    const std::vector<int> values{4, 8, 12};
    std::copy(values.begin(), values.end(),
              std::ostream_iterator<int>(std::cout, ","));
    std::cout << '\n';
}
4,8,12,

std::ostream_iterator に渡した区切り文字は、最後の要素の後にも出力されるため、この例では改行の前にカンマが残ります。範囲が空の場合は何も出力されません。末尾の区切り文字を避けたい場合は、別の区切り文字を選ぶか、区切りを個別に制御してください。範囲をストリームに出力するだけなら、この方法は簡潔です。

std::for_each で vector の要素を出力する

std::for_each は、イテレーターで指定した範囲の各要素に、渡された関数を一度ずつ呼び出します。ラムダ式を使うと、呼び出し箇所で出力処理を確認できます。

このセクションのコードと表示されるラベルや出力は英語のままです。

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    const std::vector<int> values{2, 4, 6};
    std::for_each(values.begin(), values.end(), [](int value) {
        std::cout << value << ';';
    });
    std::cout << '\n';
}
2;4;6;

この例のラムダ式は、最後の値を含め、各値の後にセミコロンを出力します。要素の間だけに句読点を入れたい場合は、区切り文字の状態をキャプチャする方法もあります。範囲が空ならラムダ式は一度も呼び出されません。

vector を出力する関数を再利用する

プログラム内の複数箇所で同じ書式を使う場合は、関数にまとめると便利です。このテンプレートは、各要素を operator<< で出力ストリームに挿入できることを条件に、異なる要素型の vector を受け取れます。

このセクションのコードと表示されるラベルや出力は英語のままです。

#include <iostream>
#include <vector>

template <typename T>
void printVector(const std::vector<T>& values) {
    bool first = true;
    for (const auto& value : values) {
        if (!first) {
            std::cout << ' ';
        }
        std::cout << value;
        first = false;
    }
    std::cout << '\n';
}

int main() {
    const std::vector<char> letters{'C', '+', '+'};
    printVector(letters);
}
C + +

このヘルパーは要素の間だけに空白を入れ、vector が空の場合も改行を出力します。独自の型を使う場合は、ヘルパーを呼び出す前に、その型に適したストリーム挿入演算子を定義してください。

vector の出力方法を選ぶ

要素の位置が必要な場合や、at() による範囲チェックが必要な場合は、インデックス付きループを使います。各値を順に処理するだけなら、範囲ベースのループが分かりやすい選択肢です。範囲をそのままストリームに出力するには std::copy を使えますが、末尾にも区切り文字が付く点に注意してください。各要素に呼び出し可能な処理を適用する場合は std::for_each が適しています。複数箇所で同じ書式を使うなら、再利用できる関数にまとめます。選択の基準は読みやすさ、範囲チェックの動作、再利用のしやすさです。どの方法が常に速いという根拠はありません。