プログラミング

C++のstd::vector完全ガイド

std::vector は、C++ 標準ライブラリに含まれるコンテナで、動的にサイズを変更できる配列を提供します。配列は通常、最初に固定サイズを持ちますが、std::vector はそのサイズを動的に変更できるため、メモリ管理が容易で柔軟です。このコンテナは非常に便利で、特に要素数が事前にわからない場合や、頻繁に要素を追加・削除する必要がある場合に最適です。

1. std::vector の基本

std::vector は、要素を順番に格納する動的配列のようなものです。最も基本的な特徴は、必要に応じて自動的にサイズが変更される点です。最初に指定したサイズよりも多くの要素を格納しようとすると、std::vector は内部的に配列のサイズを増やして、新たな要素を格納できるようにします。

cpp
#include #include int main() { std::vector<int> vec; // 空のベクターを作成 // 要素の追加 vec.push_back(10); vec.push_back(20); vec.push_back(30); // 要素の表示 for (int i : vec) { std::cout << i << " "; } return 0; }

このコードは、std::vector に対して push_back メソッドを使って要素を追加し、それらの要素を表示します。push_back は、ベクターの末尾に新しい要素を追加するメソッドです。

2. ベクターの主な操作

2.1 要素へのアクセス

std::vector の要素にアクセスする方法はいくつかあります。

  • インデックスを使う方法 (vec[i])

  • at() メソッドを使う方法 (vec.at(i))

  • イテレータを使う方法

cpp
std::vector<int> vec = {10, 20, 30, 40}; std::cout << vec[1] << std::endl; // インデックスを使ったアクセス std::cout << vec.at(2) << std::endl; // at() を使ったアクセス

at() メソッドは、インデックスが範囲外であった場合に例外 (std::out_of_range) をスローするため、安全に使用できます。一方、[] 演算子は範囲外アクセス時に未定義動作を引き起こす可能性があるため注意が必要です。

2.2 ベクターのサイズと容量

std::vector はサイズ(要素の数)と容量(確保されているメモリの量)を管理します。size() メソッドで現在のサイズを、capacity() メソッドで現在確保されているメモリ容量を取得できます。

cpp
std::vector<int> vec = {1, 2, 3, 4}; std::cout << "Size: " << vec.size() << std::endl; // 要素数 std::cout << "Capacity: " << vec.capacity() << std::endl; // 容量

std::vector の容量は、要素が追加されると必要に応じて増加します。容量が増えるタイミングは、実装によって異なりますが、通常、容量は倍増することが多いです。

2.3 要素の削除

std::vector から要素を削除するには、いくつかの方法があります。

  • pop_back() メソッドで末尾の要素を削除

  • erase() メソッドで特定の位置の要素を削除

  • clear() メソッドで全要素を削除

cpp
std::vector<int> vec = {10, 20, 30, 40}; vec.pop_back(); // 末尾の要素を削除 std::cout << "After pop_back: "; for (int i : vec) { std::cout << i << " "; } vec.erase(vec.begin()); // 最初の要素を削除 std::cout << "\nAfter erase: "; for (int i : vec) { std::cout << i << " "; } vec.clear(); // 全ての要素を削除 std::cout << "\nAfter clear: "; std::cout << vec.size() << std::endl;

pop_back() は、ベクターの末尾から要素を削除する最も簡単な方法です。erase() を使用すると、任意の位置にある要素を削除できます。また、clear() はベクターの全ての要素を削除し、サイズを 0 にします。

3. ベクターのイテレータ

std::vector では、イテレータを使って要素を順番に処理することができます。イテレータは、ポインタのように機能し、begin() で最初の要素、end() で最後の要素の後ろを指します。

cpp
std::vector<int> vec = {10, 20, 30, 40}; // イテレータを使ったループ for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; }

このコードは、イテレータを使用してベクターのすべての要素を表示します。イテレータを使うことで、範囲外アクセスを防ぐことができ、ポインタ操作に似た方法で要素にアクセスできます。

4. std::vector の利点と欠点

4.1 利点

  • 動的サイズ変更: std::vector は、要素数が増えても自動的にサイズを変更し、メモリ管理を内部で行うため、開発者が手動でサイズ変更を行う必要はありません。

  • ランダムアクセス: 配列のようにインデックスを使って任意の要素に高速でアクセスできます。

  • 効率的なメモリ管理: 内部的に、要素数に合わせてメモリを自動で管理し、追加や削除も効率的に行えます。

4.2 欠点

  • メモリ使用量: std::vector はメモリを動的に割り当てるため、要素数に対して余分なメモリを確保することがあります。特に容量を増やす際に、新しいメモリを確保して古いデータを移動する必要があり、これがコストとなる場合があります。

  • 挿入・削除のコスト: ベクターの途中に要素を挿入または削除すると、後続の要素を移動させる必要があるため、特に大きなベクターではパフォーマンスに影響が出ることがあります。

5. std::vector と他のコンテナとの比較

C++ には他にもいくつかのコンテナがあり、std::vector と比較することでその特徴がより明確になります。例えば、std::list は双方向リストであり、要素の挿入・削除に優れていますが、ランダムアクセスには不向きです。一方、std::deque は両端からの挿入・削除に適していますが、メモリの管理が少し複雑です。

std::vector はランダムアクセスが高速であり、順番にデータを処理する際に非常に効率的です。そのため、アクセスパターンが連続している場合に特に有用です。

6. 結論

std::vector は、C++ において非常に強力なコンテナであり、多くの状況で便利に使えます。その動的なサイズ変更、ランダムアクセスの高速性、そして簡単な操作方法により、多くのプログラムで標準的な選択肢となっています。しかし、挿入・削除のコストが高くなる場合や、メモリ使用量に敏感なアプリケーションでは、他のコンテナを選択することも考慮する必要があります。

Back to top button