
C++入門|vectorクラスとlistクラスの違い
vectorは番号で探しやすい修行データボード、listは隊列の組み替えに強い戦士名簿。STLは目的に合わせて使い分けることで力を発揮します。
STLには、複数のデータをまとめて管理するための便利なクラスが用意されています。
その中でも、vector と list はどちらも複数のデータを順番に保存できるため、最初はとても似ているように見えます。
vector は、配列を使いやすく発展させたようなクラスです。
データを順番に並べ、0番目、1番目、2番目というように番号でアクセスしやすいのが特徴です。
一方、list は、要素同士が前後につながった隊列のようなクラスです。
先頭や末尾への追加、途中の要素の挿入や削除を考えやすい構造になっています。
ドラゴンボール風にたとえるなら、vector は修行司令室にある番号付きの戦闘力ボードです。
1番目の戦士、2番目の戦士、3番目の戦士というように、番号でパッと確認するのに向いています。
list は、戦士たちが実際に並んでいる修行隊列です。
先頭の戦士を外したり、途中に別の戦士を入れたり、隊列そのものを組み替えるような場面に向いています。
今回の学習では、vector と list の共通点と違いを、イテレータを使った表示、list による要素削除を通して確認していきます。
| 比較項目 | vector | list |
|---|---|---|
| 基本イメージ | 番号付きの動的配列 | 前後につながる隊列 |
| 添字アクセス | できる | できない |
| イテレータ | 使える | 使える |
| 末尾への追加 | 得意 | できる |
| 途中への挿入や削除 | 要素移動が発生しやすい | 得意 |
| removeメンバ関数 | ない | ある |
| 向いている場面 | 番号で要素を取り出したい場面 | 並びの変更や削除が多い場面 |
vectorとlistはどちらもSTLのコンテナ
vector と list は、どちらもSTLのコンテナです。
コンテナとは、複数のデータを入れて管理する入れ物のことです。
vector と書けば、文字列を複数管理する vector になります。
list と書けば、文字列を複数管理する list になります。
どちらもテンプレートを使ったクラスなので、string だけでなく int や double、自作クラスなども扱えます。
たとえば、技名を管理するなら string 型を使えます。
戦闘力を管理するなら int 型を使えます。
vector<string> techniqueVector;
list<string> techniqueList;この2つは、どちらも文字列を複数保存できます。
ただし、内部の考え方や得意な操作は違います。
vector は配列の延長として考えるとわかりやすく、番号で管理しやすい構造です。
list は隊列として考えるとわかりやすく、要素の追加や削除によって並びが変化する場面に向いています。
図:vectorは番号付きボード、listは戦士の隊列

この図が示していること
この図では、vector と list の基本的な違いを表しています。
vector は、番号付きのデータボードのように、添字を使って要素を扱いやすい構造です。
list は、要素同士がつながった隊列のように、途中の挿入や削除を考えやすい構造です。
どちらも複数のデータを管理できますが、使う目的によって選び分けることが大切です。
vectorとlistを使ったサンプルプログラム
ここでは、vector と list の両方を使うサンプルを見ていきます。
vector には、表示用の技名を2つ保存します。
list には、隊列として管理する気の種類を3つ保存します。
そのあと、vector の内容はイテレータで表示します。
list では、先頭要素の値をもとに remove を使って削除し、残った要素を表示します。
プロジェクト/ファイル名: Chap6_07/main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <list>
using namespace std;
int main(int argc, char** argv) {
// 技名を番号付きで管理するvector
vector<string> techniqueVector;
// 気の隊列を管理するlist
list<string> kiList;
// vectorに技名を追加する
techniqueVector.push_back("青白い気弾");
techniqueVector.push_back("癒しの光");
// listに気の種類を追加する
kiList.push_back("亀仙流の気");
kiList.push_back("神流の癒し");
kiList.push_back("界王流の重力");
// vector用のイテレータを宣言する
vector<string>::iterator vectorItr;
// list用のイテレータを宣言する
list<string>::iterator listItr;
// vectorの要素を表示する
cout << "--- vectorの技名表示 ---" << endl;
for (vectorItr = techniqueVector.begin(); vectorItr != techniqueVector.end(); vectorItr++) {
cout << *vectorItr << endl;
}
// listの先頭を指す
listItr = kiList.begin();
// listの中から、listItrが指している値と同じ要素を削除する
kiList.remove(*listItr);
// listの要素を表示する
cout << "--- listの隊列表示 ---" << endl;
for (listItr = kiList.begin(); listItr != kiList.end(); listItr++) {
cout << *listItr << endl;
}
// プログラムが正常に終わったことを示す
return 0;
}実行結果
--- vectorの技名表示 ---
青白い気弾
癒しの光
--- listの隊列表示 ---
神流の癒し
界王流の重力このプログラムでは、vector と list の両方でイテレータを使っています。
vector::iterator vectorItr は、vector の要素を順番に指すためのイテレータです。
list::iterator listItr は、list の要素を順番に指すためのイテレータです。
vector でも list でも、begin から end までイテレータを進めることで、すべての要素を順番に表示できます。
for (vectorItr = techniqueVector.begin(); vectorItr != techniqueVector.end(); vectorItr++) {
cout << *vectorItr << endl;
}
for (listItr = kiList.begin(); listItr != kiList.end(); listItr++) {
cout << *listItr << endl;
}このように、イテレータを使って要素をたどれる点は、vector と list の共通点です。
vectorでもイテレータは使える
前回 list を学んだとき、イテレータは list の要素をたどるために使いました。
ただし、イテレータは list だけのものではありません。
vector でもイテレータを使えます。
vector<string>::iterator vectorItr;このように宣言した vectorItr は、vector の要素を指すためのイテレータです。
vector は添字でもアクセスできます。
techniqueVector[0]
techniqueVector[1]しかし、イテレータを使って次のように順番に表示することもできます。
for (vectorItr = techniqueVector.begin(); vectorItr != techniqueVector.end(); vectorItr++) {
cout << *vectorItr << endl;
}begin は先頭要素を指すイテレータを返します。
end は最後の要素の次を表すイテレータを返します。
そのため、vectorItr が end に到達するまで処理を繰り返せば、vector の全要素を表示できます。
ドラゴンボール風に言えば、vector は番号付きの修行データボードですが、イテレータというスカウター照準を使って、左から右へ順番に確認することもできるわけです。
listではremoveを使って要素を削除できる
サンプルのlist側では、removeを使って要素を削除しています。
listItr = kiList.begin();
kiList.remove(*listItr);まず、listItr = kiList.begin(); によって、listItr は list の先頭要素を指します。
この時点で、kiList の中身は次のようになっています。
亀仙流の気
神流の癒し
界王流の重力listItr は先頭の 亀仙流の気 を指しています。
そのあと、次の処理を実行します。
kiList.remove(*listItr);ここで、*listItr は listItr が指している要素の値を表します。
つまり、この場合は 亀仙流の気 です。
kiList.remove(*listItr); は、kiList の中から 亀仙流の気 と同じ値の要素を削除します。
そのため、削除後のlistは次のようになります。
神流の癒し
界王流の重力ここで注意したいのは、remove はイテレータの位置そのものを指定して削除する関数ではない、という点です。
remove は、指定した値と同じ要素を削除します。
今回のプログラムでは、先頭の値が 亀仙流の気 であり、その値は1つだけなので、先頭要素が削除されたように見えます。
もし同じ値が複数入っていれば、remove はその値と一致する要素をまとめて削除します。
| listの状態 | 処理 | 結果 |
|---|---|---|
| 亀仙流の気、神流の癒し、界王流の重力 | remove(亀仙流の気) | 神流の癒し、界王流の重力 |
| 亀仙流の気、神流の癒し、亀仙流の気 | remove(亀仙流の気) | 神流の癒し |
vector には、list の remove のようなメンバ関数はありません。
vector で要素を削除する場合は、別の方法を使います。
ここでは、list は値を指定して要素を削除できる remove メンバ関数を持っている、という点を押さえておきましょう。
図:listのremoveで値を削除する

この図が示していること
この図では、list の先頭要素をイテレータで確認し、その値を remove に渡して削除する流れを表しています。
listItr が先頭の 亀仙流の気 を指しているため、*listItr は 亀仙流の気 になります。
kiList.remove(*listItr) を実行すると、kiList の中から 亀仙流の気 と同じ値の要素が削除されます。
remove は、イテレータの位置そのものではなく、指定した値と一致する要素を削除する関数である点が大切です。
vectorとlistの共通点
vector と list は構造が違いますが、共通している部分もあります。
まず、どちらもSTLのコンテナです。
そのため、複数のデータをまとめて管理できます。
また、どちらもテンプレートで作られているので、扱う型を指定できます。
vector<string> techniqueVector;
list<string> kiList;このように、string を指定すれば文字列を管理できます。
int を指定すれば整数を管理できます。
さらに、どちらも push_back で末尾に要素を追加できます。
techniqueVector.push_back("青白い気弾");
kiList.push_back("亀仙流の気");そして、どちらもイテレータを使って先頭から終端までたどることができます。
begin()
end()共通点を整理すると、次のようになります。
| 共通点 | 内容 |
|---|---|
| STLのコンテナである | 複数のデータを管理できる |
| テンプレートで型を指定する | vector や list のように書ける |
| push_backが使える | 末尾に要素を追加できる |
| beginとendが使える | イテレータで範囲をたどれる |
| イテレータで値を取り出せる | *iterator で要素の値を参照できる |
vector と list は、使い方がまったく別物というわけではありません。
STLコンテナとして共通した操作も多くあります。
vectorとlistの違い
vector と list の大きな違いは、データの管理方法です。
vector は、配列の延長として考えるとわかりやすいクラスです。
要素が順番に並び、添字を使ってアクセスできます。
techniqueVector[0]
techniqueVector[1]このように、何番目の要素かがわかっている場合に扱いやすいです。
一方、list は添字でアクセスできません。
要素同士がつながるように管理されているため、イテレータで順番にたどる使い方が基本になります。
for (listItr = kiList.begin(); listItr != kiList.end(); listItr++) {
cout << *listItr << endl;
}また、list は任意の位置での挿入や削除を考えやすいコンテナです。
remove、push_front、pop_front、insert など、隊列を組み替えるような操作に向いたメンバ関数を持っています。
| 違い | vector | list |
|---|---|---|
| 管理の考え方 | 配列の延長 | 前後につながる隊列 |
| 添字アクセス | できる | できない |
| 要素の削除 | removeメンバ関数はない | removeメンバ関数がある |
| 先頭への追加 | 得意とは限らない | push_frontが使える |
| 途中への挿入 | 要素移動が発生しやすい | insertとイテレータで扱いやすい |
| 主な使い方 | 番号で要素を扱う | 並びの変更を扱う |
ドラゴンボール風に言えば、vector は修行記録を番号で管理する台帳です。
list は戦士の実際の隊列です。
番号で何番目かを素早く見たいなら vector が合っています。
先頭を外したり、途中を差し替えたり、隊列の並びを変えたいなら list が合っています。
listの主なメンバ関数
list には、要素の追加や削除を行うための便利なメンバ関数があります。
| メンバ関数 | 意味 |
|---|---|
| push_front(値) | 先頭に要素を追加する |
| push_back(値) | 末尾に要素を追加する |
| pop_front() | 先頭の要素を削除する |
| pop_back() | 末尾の要素を削除する |
| insert(イテレータ, 値) | 指定位置の直前に要素を挿入する |
| remove(値) | 指定した値と同じ要素を削除する |
| clear() | すべての要素を削除する |
push_front は、先頭に要素を追加します。
push_back は、末尾に要素を追加します。
pop_front は、先頭の要素を削除します。
pop_back は、末尾の要素を削除します。
insert は、イテレータで指定した位置の直前に要素を挿入します。
remove は、指定した値と同じ要素を削除します。
clear は、すべての要素を削除します。
list は、このように並びを変化させる操作が豊富です。
そのため、要素を追加したり削除したりする場面で使いやすいクラスです。
図:vectorとlistの使い分け

この図が示していること
この図では、vector と list をどのように使い分けるかを表しています。
vector は、番号で要素にアクセスしたい場面に向いています。
list は、先頭への追加、途中への挿入、要素の削除など、隊列を組み替えるような操作に向いています。
STLでは、どのコンテナを使うかによって、プログラムの書きやすさや処理の考え方が変わります。
サンプルプログラムの流れを確認する
今回のサンプルでは、まず vector に2つの技名を追加しています。
techniqueVector.push_back("青白い気弾");
techniqueVector.push_back("癒しの光");そのあと、vector のイテレータで内容を表示しています。
for (vectorItr = techniqueVector.begin(); vectorItr != techniqueVector.end(); vectorItr++) {
cout << *vectorItr << endl;
}実行結果では、次のように表示されます。
青白い気弾
癒しの光次に、list には3つの気の種類を追加しています。
kiList.push_back("亀仙流の気");
kiList.push_back("神流の癒し");
kiList.push_back("界王流の重力");この状態で、listItr を先頭に合わせます。
listItr = kiList.begin();先頭の値は 亀仙流の気 です。
その値を使って、removeで削除します。
kiList.remove(*listItr);その結果、亀仙流の気 が削除され、list には 神流の癒し と 界王流の重力 が残ります。
最後に、list のイテレータで内容を表示します。
for (listItr = kiList.begin(); listItr != kiList.end(); listItr++) {
cout << *listItr << endl;
}実行結果では、次のように表示されます。
神流の癒し
界王流の重力この流れから、vector でも list でもイテレータを使えること、そして list では remove による要素削除ができることを確認できます。
vectorとlistで身につけたい使い分けの感覚
vector と list は、どちらも複数のデータを扱える便利なSTLコンテナです。
しかし、何をしたいかによって、選ぶべきコンテナは変わります。
要素を番号で扱いたいなら vector が向いています。
たとえば、techniqueVector[0] のように何番目の技かを指定して取り出したい場合です。
一方で、先頭や途中の要素を追加したり削除したりする操作が多いなら list が向いています。
list は、隊列の中から特定の値を削除したり、イテレータで位置を指定して挿入したりする考え方に合っています。
ドラゴンボール風に言えば、vector は修行データを番号で管理する記録ボードです。
list は、戦士たちの並びを柔軟に変えられる出撃隊列です。
どちらも便利ですが、得意分野は違います。
STLを使うときは、ただデータを入れられればよいと考えるのではなく、そのデータをあとでどのように使うのかを考えることが大切です。
番号でよく取り出すのか。
途中でよく削除するのか。
先頭に追加することが多いのか。
全体を順番にたどるだけなのか。
こうした使い方を考えて、vector と list を選び分けると、C++のデータ管理がよりわかりやすく、扱いやすくなります。
