水瓶座列車

どこまで行けるか、とりあえず発車します。

C++のvector<>コンテナの使い方と応用について解説

 

C++のvector<>コンテナは、C言語の配列と似ていますが、配列よりもかなり扱いやすいです。

例えば、vector<>のサイズを意識せずとも、先頭要素を示すbegin()や最後の要素を示すend()など、

vector<>コンテナを操作する関数がいろいろあります。

ここでは、vector<>コンテナの使い方と応用について、解説していきます。

 

 

  1. C++のvector<>コンテナについて
  2. C++のvector<>コンテナの宣言のやり方
  3. C++のvector<>コンテナのイテレータの宣言のやり方
  4. C++のvector<>コンテナの操作について
  5. C++のvector<>コンテナの操作の使い方とプログラム例
  6. vector<>コンテナの応用した使い方
  7. 最後に

 

 

 

1.C++のvector<>コンテナについて

 

vector<>は、C++標準テンプレートライブラリ(STL)に含まれるコンテナの一種で、

vector<>の扱い方は、、C言語の配列と同じイメージです。

配列と異なることは、要素の数を動的に変更できたり、メモリ管理も自動的に行われます。

 

なので、C++では、C言語の配列より、vector<>を使用する方が、かなり便利です。

また、C言語のポインタと同じ考え方で、C++ではイテレータがあります。

イテレータを使用することで、vector<>の要素を簡単に追加・削除したり、

先頭要素、最後尾要素にも簡単にアクセスすることができます。

C言語の配列より、かなり扱いやすいので、C++では、配列よりもvector<>を使用する方が良いです。

 

 

2.C++のvector<>コンテナの宣言のやり方

 

vector<>を使用するには、

・vector.h をインクルードする。

・namespace std; でネームスペースを設定する。

をする必要があります。

 

そして、vector<>の宣言のやり方は、下記のような感じになります。

vector<型> 変数名();
vector<型> 変数名(要素数);

 

具体的には、下記のように宣言します。

vector<int> vCnt;
vector<int> vNum(10);
vector<char> vChar(10);

 

C言語の配列では、要素数もあらかじめ宣言しておく必要がありますが、

vector<>の場合は、必ずしも要素数を決める必要がなく、プログラムが進むことによって、

要素を追加していくことができます。

また、vectorの要素数を最初に宣言したとしても、プログラム内で要素追加や要素削除の操作を行うと、

必ずしもこの宣言で行った要素数になっているとは限らないので注意が必要です。

 

 

3.C++のvector<>コンテナのイテレータの宣言のやり方

 

vector<>を使用する上で、イテレータの考え方が必要になります。

イテレータとは、vector<>などのコンテナにアクセスするための目印のようなもので、

扱い方のイメージとしては、C言語のポインタ操作のような感じです。

ただ、C言語のポインタは、メモリのアドレスを指し示すもので、メモリ操作を直接扱うことができますが

イテレータは、メモリアドレスを直接扱うのではなく、コンテナが提供するインターフェースを通して、

要素にアクセスします。

 

イテレータの宣言のやり方は、下記のような感じです。

vector<int>::iterator itr;

これは、int型のvector<>をアクセスするためのイテレータitr変数を宣言しています。

他にもchar型、bool型など使用したい型で宣言することができます。

 

補足として、C++11以降では、

auto itr = vNum.begin();

のように、auto を使用すると、右辺の型に合わせてコンパイラが自動的に変換してくれます。

 

 

4.C++のvector<>コンテナの操作について

 

ここでは、よく使用されるvector<>操作を、下表にまとめました。

関数名 説明
begin() vectorの先頭要素を指すイテレータを返す。
end() vectorの終端の次の要素を指すイテレータを返す。
end()が指す要素は、vectorの要素ではない。)
at() 文字列の先頭から指定された文字数分を別の配列に上書きコピーする。
size() vectorの要素数を返します。
empty()  vectorが空かどうかを判定します。
push.back() 末尾に要素を追加します。
insert() 指定した位置に要素を挿入します。
pop.back() 末尾の要素を削除します。
erase() 指定したイテレータまたは範囲の要素を削除します。
clear() 全ての要素を削除します。

 

操作する関数は、上表の他にもありますが、最低限この表の操作を覚えておくと、

vector<>操作に困らないと思います。

 

 

5.C++のvector<>コンテナの操作の使い方とプログラム例

 

5.1 begin()/end()、at()の使い方

 

begin() / end()、at() のイメージは、下図のような感じです。

 

begin() / end()、at() の使い方は、下記のような感じです。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
vector<int> vNum(10);
vector<int>::iterator itr = vNum.begin(); // <ーー (1)
int num;

for( num=0 ; itr != vNum.end(); num++, itr++ ){ // <ーー(2)
*itr = num;
}

num = 0;
for( itr=vNum.begin(); itr != vNum.end(); itr++,num++ ){
printf("vector[%d] = %d\n", num, vNum.at(num) ); // <ーー(3)
}

return 0;
}

 

上記は、vector<>の先頭から順に0~9を格納した後、vector<>の値を表示するプログラムです。

(1)で、vector<int>型のイテレータであるitr変数を宣言して、

初期値にvNum変数の先頭要素を指すbegin()を設定しています。

 

(2)のfor文では、イテレータをインクリメントしながら、vNum変数の最後尾の要素を指すend()まで、

vNum変数に値を入れる処理を繰り返します。

 

(3)で、vector<>の全ての要素値をfor文でat()を使用して表示しています。

(C++の標準出力は、coutを使用しますが、私はprintf()が好きなので、

ここでは、printf()を使用します。)

 

 

5.2 vector<>の要素数を調べるsize()の使い方

 

size()は、vector<>の要素数を戻り値として返します。

size()の使い方は、下記のような感じです。

#include <iostream>
#include <vector>

using namespace std;

int main()
{ vector<int> vA;
vector<int> vB = {0,1,2,3,4};
printf("vA size() = %lu \n", vA.size()); // (1)
printf("vB size() = %lu \n", vB.size()); // (2)
vA.push_back(10); printf("vA size() = %lu \n", vA.size()); // (3)
return 0;
}

 

(1)では、変数vA に要素が無いので、サイズは0を表示します。

(2)では、変数vB の要素数で、サイズは5を表示します。

(3)では、直前に変数vAにpush_back()で要素を追加しましたので、サイズは1を表示します。

()内の10は、要素の値になります。push_back()については、後で解説します。

 

 

5.3 vector<>が空かどうか判定するempty()の使い方

 

empty()は、戻り値がbool型で、vector<>のサイズが0の場合は、真(true)を返し、

サイズが0でない場合は偽(false)を返します。

 

empty()の使い方は、下記のような感じです。

#include <iostream>
#include <vector>

using namespace std;

int main()
{ vector<int> vA;
vector<int> vB = {0,1,2,3,4};
printf("vA empty() = %d \n", vA.empty()); // (1)
printf("vB empty() = %d \n", vB.empty()); // (2)
vA.push_back(10); printf("vA empty() = %d \n", vA.empty()); // (3)
return 0;
}

 

(1)では、変数vA に要素が無いので、真(true)を表示します。

(2)では、変数vB は要素があるので、偽(false)を表示します。

(3)では、直前に変数vAにpush_back()で要素を追加しましたので、偽(false)を表示します。

()内の10は、要素の値になります。push_back()については、後で解説します。

 

 

5.4 vector<>の要素を追加するpush_back()/insert()の使い方

 

push_back() は、引数で指定した値をvector<>の最後尾に追加します。

insert()は、第一引数で挿入したい位置のイテレータを指定し、

第二引数で、値や別vector変数の範囲を指定します。

 

push_back() と insert() の使い方は、下記のような感じです。

#include <iostream>
#include <vector>
using namespace std;
void printVector ( vector<int> vec )
{
int iCnt = 0;
vector<int>::iterator itr = vec.begin();
for( itr=vec.begin(); itr != vec.end(); itr++ ) {
printf("vector[%d] = %d\n", iCnt, vec.at(iCnt) );
iCnt++;
}
}
int main()
{
vector<int> vNum = {0,1,2,3};
int iCnt;

// push_back
printf("\n push_back(a) \n");
iCnt = 0;
vNum.push_back(10); // <ーー(1)
printVector ( vNum );
// insert
printf("\n insert \n");
vNum.insert(vNum.begin()+3, 100); // <ーー(2)
printVector ( vNum );
// insert 2
printf("\n insert 2 \n");
vector<int> vInsert = { 200, 210 };
vNum.insert(vNum.begin()+3, vInsert.begin(), vInsert.end() ); // <ーー(3)
printVector ( vNum );

return 0;
}

 

(1)の push_back()で、下図のように、vector<>の最後尾に値10を追加します。

追加に伴い、vector<>のサイズも1増加します。

 

(2)の insert()で、下図のようにvector<>の3番目に値100を追加します。

追加に伴い、vector<>のサイズも1増加します。

 

(3)のinsert()で、下図のように第二引数で指定されたvector<>の値全てを、

第一引数で指定された位置に挿入します。

追加に伴い、vector<>のサイズも挿入した分、増加します。

 

 

5.5 vector<>の要素を削除するpop_back()/erase()の使い方

 

pop_back() は、引数で指定した値をvector<>の最後の要素を削除します。

erase()は、第一引数で挿入したい位置のイテレータの要素を削除したり、

第一引数から第二引数までの要素を削除します。

 

 

pop_back() と erase() の使い方は、下記のような感じです。

#include <iostream>
#include <vector>
using namespace std;
void printVector ( vector<int> vec )
{
int iCnt = 0;
vector<int>::iterator itr = vec.begin(); for( itr=vec.begin(); itr != vec.end(); itr++ ){
printf("vector[%d] = %d\n", iCnt, vec.at(iCnt) );
iCnt++;
}
printf("vector.size = %lu\n",  vec.size() );
}
int main()
{
   vector<int> vNum = { 0,1,2,3,4,5 };
   vector<int>::iterator itr = vNum.begin();
    int iCnt;
    // pop_back
   printf("\n pop_back \n");
   vNum.pop_back();     // <ーー(1)
    printVector ( vNum );
    // erase
  printf("\n erase \n");
   vNum.erase( vNum.begin()+2 );  // <ーー(2)
    printVector ( vNum );
    // erase 2
  printf("\n erase 2 \n");
   vNum.erase( vNum.begin(),vNum.begin()+2);  // <ーー(3)
    printVector ( vNum );

  return 0;
}

 

(1)の pop_back()で、下図のように、vector<>の最後の要素を削除します。

削除に伴い、vector<>のサイズも1減少します。

 

(2)の erase()で、下図のようにvector<>の3番目の要素を削除します。

削除に伴い、vector<>のサイズも1減少します。

 

(3)のerase()で、下図のように第一引数から第二引数で指定されたイテレータまでの要素を削除します。

削除に伴い、削除した要素分のサイズも減少します。

 

 

5.6 vector<>の要素を全削除するclear()の使い方

 

clear()は、vector<>の要素数を全て削除します。

clear()の使い方は、下記のような感じです。

#include <iostream>
#include <vector>

using namespace std;

int main()
{ vector<int> vNum = {0,1,2,3,4};
// (1) clear前のサイズを表示
printf("before size %lu \n", vNum.size());
printf("before empty %d \n", vNum.empty());
vNum.clear();
// (2) clear後のサイズを表示
printf("after size %lu \n", vNum.size());
printf("after empty %d \n", vNum.empty());
return 0; }

 

(1)では、clear()前のvector<>変数のvNumのサイズと空状態を表示しています。

この時は、サイズは5で、空ではないのでfalseの0を表示します。

 

(2)では、clear()後のvector<>変数のvNumのサイズと空状態を表示しています。

この時は、サイズは0で、空なのでtrueの1を表示します。

 

 

6.vector<>コンテナの応用した使い方

 

vector<>の応用した使い方としては、

vector<vector<int>> vVecIntNum[5][5];
vector<Myclass> vMyClass;

のように、vectorの型には、vector<>自体やクラスも設定することができます。

vVecInt[5][5]は、C言語でいうとa[5][5]のような2次元配列になります。

 

 

6.1 vector<>コンテナの2次元配列の使い方

 

vector<>の2次元配列の使い方は、下記のような感じになります。

#include <iostream>
#include <vector>
using namespace std;
int main()
{ vector<vector<int>> vNum = { {1,2,3}, {4,5,6}, {7,8,9} };
vector<vector<int>>::iterator itr;
vector<int>::iterator itr2;
int iCnt,iCnt2;
for( iCnt=0,itr=vNum.begin(); itr < vNum.end(); iCnt++, itr++ )
{
for( iCnt2=0, itr2=vNum[iCnt].begin(); itr2 < vNum[iCnt].end(); iCnt2++, itr2++ )
{
printf("vNum[%d][%d] = %d\n",iCnt, iCnt2, *itr2 );
}
}
return 0;
}

 

 

6.2 vector<>コンテナのクラス型の使い方

 

MyClassクラスを氏名や年齢、住所を管理するクラスとした場合、

MyClassクラスをvector<>で管理することで、名簿として管理することができます。

vector<>のクラス型の使い方は、下記のような感じになります。

#include <iostream>
#include <vector> using namespace std;
class MyClass {
public:
MyClass(){};
~MyClass(){};
void setName( string a ){ name=a; }
void setAge( int a ){ age=a; }
void setAddress( string a ){ address=a; }
string getName(){ return name; }
int getAge(){ return age; }
string getAddress( ){ return address; } private:
string name;
int age;
string address;
}; int main()
{
string strName[] = {"name1", "name2", "name3","name4"};
int iAge[] = { 23, 43, 34, 17 };
string strAddress[] = {"tokyou", "osaka", "nara", "kanagawa"}; vector<MyClass*> vMyClass(4);
vector<MyClass*>::iterator itr;
MyClass *cMyClass;
int iCnt;
// (1) MyClassクラスのメモリを確保してデータを格納し、vector<>に格納する。
for( iCnt=0, itr=vMyClass.begin(); itr < vMyClass.end(); iCnt++, itr++ )
{
cMyClass = new MyClass();
cMyClass->setName( strName[iCnt] );
cMyClass->setAge( iAge[iCnt] );
cMyClass->setAddress( strAddress[iCnt] );
*itr = cMyClass;
}
//(2)MyClassクラスのメンバ変数の値を表示する。
for( iCnt=0, itr=vMyClass.begin(); itr < vMyClass.end(); iCnt++, itr++ )
{
printf("\nNo. %d\n", iCnt );
printf("name = %s\n", (*itr)->getName().c_str() );
printf("age = %d\n", (*itr)->getAge());
printf("address = %s\n", (*itr)->getAddress().c_str() );
}
//(3)MyClassクラスのメモリを開放する。
for( itr=vMyClass.begin(); itr < vMyClass.end(); itr++ )
{
delete *itr;
}
return 0;
}

 

(1)は、MyClassのメモリを確保して、メンバ変数name、age、addressに値を格納していきます。

その後、MyClassのインスタンスをvector<>の要素として格納して、要素数分繰り返します。

 

(2)は、vector<>に格納されているMyClassのメンバ変数の値を1つずつ表示しています。

 

(3)は、(1)で確保したメモリを解放しています。確保したメモリを解放しないと、

メモリリークの原因になりますので、newした場合は必ずdeleteもセットで行います。

 

 

7.最後に

 

C++のプログラミングで、配列を考える時は、まずはvector<>を使用すると良いです。

配列操作が、簡単でコード量自体も少なくなり、読みやすくなります。

 

 

<関連・おすすめ記事>

C++のクラス構造の解説とプログラミングの始め方 - 水瓶座列車

Qt5とQtCreatorをUbuntu20.04にインストールする手順と使い方を解説 - 水瓶座列車

ミニPCとラズパイの比較解説とミニPCおすすめランキング - 水瓶座列車

Linux勉強用の中古パソコンおすすめショップランキング - 水瓶座列車

C言語の始め方と基本構造、コンパイルから実行までを解説 - 水瓶座列車

C言語のデータ型と変数、関数について解説 - 水瓶座列車

C言語の繰り返し構文( while, do while, for )の解説と応用 - 水瓶座列車

C言語の演算子と優先順位の解説 - 水瓶座列車

C言語の構造体について解説 - 水瓶座列車

 

 

 

Â