[C++/STL] std::vectorクラスの使い方

※本ブログでは、商品・サービスのリンク先にプロモーションを含みます。

スポンサーリンク

std::vectorは、C++の標準テンプレートライブラリ(STL)の中核を成すコンテナの一つであり、動的配列の機能を提供します。この記事では、vectorクラスの基本的な概念から、使用方法、そしてパフォーマンスの最適化に至るまで、幅広いトピックにわたって解説します。

C++のおすすめの書籍を紹介します。

◆初学者向けの入門書

C++の機能をわかりやすく、丁寧に解説している良書です。

created by Rinker
¥4,180 (2024/02/27 20:09:11時点 楽天市場調べ-詳細)

◆中級者向けの書籍

C++の開発者が書いた本なので、C++11までの仕様が網羅的に書かれています。

◆上級者向けの書籍

C++を効率的かつ正確に使用するための最適解とガイドラインを示してくれる良書です。
各章は、特定のテクニックやアプローチに関する詳細な説明と例を含んでおり、プログラマがより良いコードを書くために一役買ってくれます。

スポンサーリンク

vectorクラスとは

vectorクラスの基本的な概念

vectorクラスは、標準テンプレートライブラリ(STL)の一部で、動的配列の機能を提供します。
動的配列とは、プログラムの実行時にサイズを変更できる配列のことを指します。
vectorは、連続したメモリ上に要素を格納し、ランダムアクセス(任意の要素に直接アクセス)が可能です。これにより、通常の配列と同様の性能、および方法で要素にアクセスできます。

vectorクラスは、要素を追加または削除する際に、自動的にメモリを割り当てたり解放したりすることができ柔軟性があります。これは、固定サイズの配列に比べて大きな利点となります。さらに、vectorクラスはテンプレートクラスであるため、様々なデータ型で使用することが可能です。

vectorクラスの重要性

vectorクラスは、高性能で柔軟性も高いため広く使用されています。配列と同じように使える一方で、サイズの動的な変更や様々な便利な操作(ソート、検索、逆順のイテレーションなど)をサポートしています。これにより、プログラマはより効率的なコードを書くことが可能になります。

また、vectorクラスはメモリ管理を自動化しているため、メモリリークのリスクを低減できます。プログラマが直接メモリを割り当てたり解放したりする必要がないため、メモリに関するエラーが発生する可能性が減少します。このように、vectorクラスは効率性、柔軟性、安全性の三つの重要な要件を満たしており、便利なクラスです。

vectorクラスの基本

vectorの作成と初期化

  • 空のvectorの作成方法
std::vector<int> vect; // 空のint型のvector

型を指定して空のvectorを作成することができます。
上記例のvect1は、何も要素を持たないため、そのサイズは0です。

  • 初期サイズを指定して作成する方法
std::vector<int> vect(10); // 10個の要素で初期化されたvector

初期サイズを持つvectorを作成することができます。この場合、各要素はデフォルト値で初期化されます。
上記例のvect2は、10個の整数が格納されており、それぞれの値は0(整数型のデフォルト値)です。

  • 初期サイズと初期値を指定して作成する方法
std::vector<int> vect(10, 5); // 10個の要素が全て5で初期化されたvector

初期サイズとともに初期値を指定することも可能です。この方法では、全ての要素が指定した値で初期化されます。上記例のvect3は、10個の整数が格納されており、それぞれの値は5に初期化されます。

  • 初期化リストで初期値を指定して作成する方法
std::vector<int> vect = {1, 2, 3, 4, 5}; // 初期化リストで初期化されたvector

C++11以降では、初期化リストを使用してvectorを初期化することができます。
上記例のvect4では、5個の整数が格納されており、それぞれ1, 2, 3, 4, 5に初期化されます。

サイズと容量の理解

vectorには「サイズ」と「容量」の2つの重要な属性があります。サイズはvectorに現在含まれる要素の数を指し、容量はvectorがメモリ上で保持している要素の最大数を意味します。

  • サイズを確認する方法

サイズはsize()メソッドを使って確認できます。

std::cout << "Size: " << vect.size(); // vect4のサイズを出力
  • 容量の確認と拡張

容量はcapacity()メソッドで確認できます。また、reserve()メソッドを使って容量を拡張することができます。

std::cout << "Capacity: " << vect.capacity(); // vectの容量を出力
vect.reserve(10); // vectの容量を少なくとも10に拡張

サイズを超える要素を追加する際、vectorは自動的に容量を増やしますが、頻繁な容量の拡張はパフォーマンスに影響を与えるため、必要な容量があらかじめ分かっている場合はreserve()を使用すると効率的です。

要素へのアクセス方法

  • インデックスによるアクセス

vectorの要素にアクセスする基本的な方法はインデックスを使用することです。これは通常の配列と同じ方法です。

int elem = vect[0]; // 最初の要素にアクセス
  • at()メソッドによる安全なアクセス

at()メソッドを使用すると、範囲外アクセス時に例外がスローされるため、より安全に要素にアクセスできます。

try{
    int elem = vect.at(10); // 範囲外アクセスの試み
}catch(std::out_of_range& e){
    std::cout << "Out of Range error: " << e.what() << '\n';
}
  • front()とback()メソッド

front()とback()メソッドは、それぞれvectorの最初と最後の要素に簡単にアクセスするための方法です。

int first = vect.front(); // 最初の要素
int last  = vect.back();  // 最後の要素

vectorとlistの比較

vectorとlistクラスの違い

vectorとlistの主な違いは、内部のデータ構造とその操作にあります。

  • vector

vectorは動的配列を実装しており、要素は連続したメモリブロックに格納されます。この特性により、ランダムアクセス(任意の位置の要素への直接アクセス)が高速です。

std::vector<int> vect = {1, 2, 3, 4, 5};
int elem = vect[2]; // 3番目の要素に高速アクセス

しかし、vectorの中間に要素を挿入または削除すると、後続の全要素を移動させる必要があり、これが大きなコストになります。

  • list

listはダブルリンクリストを実装しており、各要素はメモリ上の別々の場所に格納され、前後の要素へのポインタによって接続されています。このため、要素の挿入と削除が高速です。

std::list<int> list = {1, 2, 3, 4, 5};
auto it = std::next(list.begin(), 2);
list.insert(it, 6); // 3番目の位置に6を挿入

しかし、リストのランダムアクセスは効率が悪く、特定の要素にアクセスするには先頭から順にたどる必要があります。

各クラスの利点と使い分け

  • vectorの利点
  • ランダムアクセスの効率
    任意の要素へのアクセスが高速。
  • メモリ効率
    連続したメモリブロックを使用するため、メモリの