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 が適しています。複数箇所で同じ書式を使うなら、再利用できる関数にまとめます。選択の基準は読みやすさ、範囲チェックの動作、再利用のしやすさです。どの方法が常に速いという根拠はありません。