std::vector



vector

ランダムアクセス配列. 要素は連続したメモリ領域に確保される(シーケンスコンテナ)ため, イテレータでのアクセスだけでなく,従来のポインタを用いた要素アクセスも可能. さらに,動的配列であり,そのサイズを容易に変更可能. ただし,処理中にさらに要素を拡大されることを見越して,サイズ変更時に通常の配列よりも多めのメモリを確保してしまうため, 巨大で大きさが固定の領域を確保したい場合は通常の配列を用いた方がよいかもしれない.

C++のnewを用いた場合と異なり,deleteの必要はない.vector変数の有効なスコープを抜けた時点でクリアされる.

インクルード

#include <vector>

初期化(コンストラクタ)

explicit vector(const Allocator& = Allocator());
explicit vector(size_type n, const T& value= T(), const Allocator& = Allocator());
template <class InputIterator>
        vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
vector(const vector<T,Allocator>& x);

使用例

#include <iostream>
#include <vector>
using namespace std;

template<class T> 
inline void output(vector<T> x)
{
	vector<T>::iterator iter;
	for(iter = x.begin(); iter != x.end(); ++iter){
		cout << *iter << " ";
	}
	cout << endl;
}

int main(void)
{
	vector<int> a;						// 空コンテナ
	vector<int> b(5);					// サイズ5のコンテナ
	vector<int> c(5, 3);				// サイズ5のコンテナ,3で全ての要素を初期化
	vector<int> d(c.begin(), c.end());	// コンテナcのコピー
	vector<int> e(d);					// コンテナdのコピー

	a.resize(5, 1);
	output(a);
	output(b);
	output(c);
	output(d);
	output(e);
	
	return 0;
}

実行結果

1 1 1 1 1
0 0 0 0 0
3 3 3 3 3
3 3 3 3 3
3 3 3 3 3

要素アクセス([],at,front,back,begin,end,rbegin,rend)

  • [] : 通常の配列と同じオペレータ[]を用いたアクセス
    reference operator[](size_type n);
    const_reference operator[](size_type n) const;
  • at() : 範囲外アクセス時にout_of_range例外を投げる関数
    const_reference at(size_type n) const;
    reference at(size_type n);
  • front() : コンテナの最初の要素にアクセスする関数
    reference front();
    const_reference front() const;
  • back() : コンテナの最後の要素にアクセスする関数
    reference back();
    const_reference back() const;
  • begin(),end() : コンテナの最初のイテレータ,最後の次のイテレータを返す.イテレータを用いた要素アクセスに使用
    iterator begin ();
    const_iterator begin () const;
  • rbegin(),rend() : コンテナの最初の逆イテレータ,最後の次の逆イテレータを返す.イテレータを用いた要素逆順アクセスに使用
    reverse_iterator rend();
    const_reverse_iterator rend() const;
    使用例
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(void)
    {
    	vector<double> x(4);
    
    	// アクセス方法
    	x.front() = 1.0;
    	x.at(1) = 2.0;
    	x[2] = 3.0;
    	x.back() = 4.0;
    
    	// 通常の配列のように要素にアクセス
    	for(int i = 0; i < (int)x.size(); ++i){
    		cout << x[i] << " ";
    	}
    	cout << endl;
    
    	// イテレータを用いた配列アクセス
    	vector<double>::iterator iter;
    	for(iter = x.begin(); iter != x.end(); ++iter){
    		cout << *iter << " ";
    	}
    	cout << endl;
    
    	// 逆向きアクセス
    	vector<double>::reverse_iterator riter;
    	for(riter = x.rbegin(); riter != x.rend(); ++riter){
    		cout << *riter << " ";
    	}
    	cout << endl;
    	
    	return 0;
    }
    実行結果
    1 2 3 4
    1 2 3 4
    4 3 2 1

領域確保(resize,reserve)

  • resize(n) : コンテナのサイズをnに変更する関数
    void resize(size_type sz, T c = T());
  • reserve(n) : コンテナの予約領域を確保する関数.実際に使える(アクセスできる)領域ではないが,ある程度確保したいサイズが決まっているならばpush_backする前にreserveで確保しておくと高速に処理できる.
    void reserve(size_type n);

サイズ確認(size,capacity,max_size,empty)

  • size() : コンテナのサイズを返す関数
    size_type size() const;
  • capacity() : コンテナの予約領域を返す関数.reserveで確保した領域サイズ.
    size_type capacity () const;
  • max_size() : コンテナが確保可能な最大サイズを返す関数.予約領域ではない.
    size_type max_size () const;
  • empty() : コンテナが空だったらtrueを返す関数.size == 0かどうかを確かめることと同義であるが,size()へのアクセスよりも高速.
    bool empty () const;
    使用例
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(void)
    {
    	vector<double> x;
    
    	// メモリ領域の予約
    	x.reserve(5);
    
    	// メモリ領域の確保
    	x.resize(3);
    
    	// 配列のサイズ
    	cout << x.size() << endl;
    
    	// 予約領域のサイズ
    	cout << x.capacity() << endl;
    
    	// 最大サイズ
    	cout << x.max_size() << endl;
    	
    	return 0;
    }
    実行結果
    3
    5
    536870911

編集(push_back,pop_back,assign,insert,erase,clear,swap)

  • push_back(val) : コンテナの最後に要素を追加
    void push_back(const T& val);
  • pop_back() : コンテナの最後の要素を削除
    void pop_back();
    使用例
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(void)
    {
    	vector<double> x;
    	x.reserve(5);
    
    	// 配列の後尾に要素を追加
    	for(int i = 0; i < 5; ++i){
    		x.push_back((double)(i+1));
    	}
    	output(x);
    
    	// 配列の最後尾の要素を削除
    	x.pop_back();
    	x.pop_back();
    	output(x);
    
    	return 0;
    }
    実行結果
    1 2 3 4 5
    1 2 3
  • assign(n, val) :
    template <class InputIterator>
     void assign(InputIterator first, InputIterator last);
    void assign(size_type n, const T& u);
    使用例
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(void)
    {
    	vector<double> x0(5), x;
    
    	// assignによる値の割り当て
    	x.assign(5, 1);
    	output(x);
    
    	double y = 1.0;
    	vector<double>::iterator iter;
    	for(iter = x0.begin(); iter != x0.end(); ++iter){
    		*iter = y;
    		y *= 1.5;
    	}
    	output(x0);
    
    	// 他のコンテナからの割り当て
    	x.assign(x0.begin()+1, x0.end()-1);
    	output(x);
    
    	// 配列からの割り当て
    	double x2[] = {10.0, 11.0, 12.0};
    	x.assign(x2, x2+3);
    	output(x);
    	
    	return 0;
    }
    実行結果
    1 1 1 1 1
    1 1.5 2.25 3.375 5.0625
    1.5 2.25 3.375
    10 11 12
  • insert() : イテレータで示された位置に要素を挿入する.
    iterator insert(iterator position, const T& val);
    void insert(iterator position, size_type n, const T& val);
    template <class InputIterator>
     void insert(iterator position, InputIterator first, InputIterator last);
    使用例
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(void)
    {
    	vector<double> x(4, 0.0);
    	vector<double> y(3, 3.0);
    	output(x);
    
    	//x.reserve(100);	// イテレータの無効化を防ぐためにあらかじめreserveしておくのも一つの手
    	int capa0 = x.capacity();
    
    	vector<double>::iterator iter = x.begin();
    
    	// 要素の挿入
    	iter = x.insert(iter+2, 1.0);	// 値のみ指定,返値は新しく挿入された要素へのイテレータ
    	output(x);
    	
    	// 要素を複数挿入
    	x.insert(iter+1, 2, 2.0);
    	output(x);
    	
    	if(capa0 != x.capacity()){
    		// コンテナサイズの変更が起こるとイテレータは無効になるので注意
    		iter = x.begin()+2;
    	}
    
    	// 他のコンテナの内容を挿入
    	x.insert(iter+3, y.begin(), y.end());
    	output(x);
    
    	// 配列を挿入
    	int z[] = { 4, 4, 4, 4 };
    	x.insert(x.begin()+7, z, z+4);
    	output(x);
    
    	return 0;
    }
    実行結果
    0 0 0 0
    0 0 1 0 0
    0 0 1 2 2 0 0
    0 0 1 2 2 3 3 3 0 0
    0 0 1 2 2 3 3 4 4 4 4 3 0 0
  • erase(iter) : イテレータで示された位置の要素を削除する.
    iterator erase(iterator position);
    iterator erase(iterator first, iterator last);
  • clear() : コンテナのクリア.全要素を削除する.
    void clear();
    使用例
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(void)
    {
    	vector<int> x(5);
    	for(int i = 0; i < (int)x.size(); ++i) x[i] = i;
    	output(x);
    	cout << "(" << x.size() << ")" << endl;
    
    	// 要素削除
    	x.erase(x.begin()+1);
    	output(x);
    	cout << "(" << x.size() << ")" << endl;
    
    	// 範囲削除
    	x.erase(x.begin()+2, x.end());
    	output(x);
    	cout << "(" << x.size() << ")" << endl;
    
    	// 全要素削除
    	x.clear();
    	cout << "(" << x.size() << ")" << endl;
    
    	return 0;
    }
    実行結果
    0 1 2 3 4
    (5)
    0 2 3 4
    (4)
    0 2
    (2)
    (0)
  • swap : 2つのコンテナのスワップ.
    void swap(vector<T,Allocator>& vec);
    使用例
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(void)
    {
    	vector<int> x;
    	vector<int> y;
    
    	for(int i = 0; i < 5; ++i){
    		x.push_back(i);
    		y.push_back(5-i);
    	}
    	output(x); output(y);
    	cout << endl;
    
    	y.swap(x);
    
    	output(x); output(y);
    	
    	return 0;
    }
    実行結果
    0 1 2 3 4
    5 4 3 2 1
    
    5 4 3 2 1
    0 1 2 3 4

従来の配列との互換性

vectorは要素がメモリ上にシークエンスに並んでいるので, 従来の配列と互換性を持つ.

vector<int> x;
	for(int i = 0; i < 5; ++i) x.push_back(i);

	int *p = &x[0];
	p[1] = 3;
	for(int i = 0; i < 5; ++i) cout << p[i] << " ";
	cout << endl;

上記のように最初の要素のポインタを用いて配列のように扱える. ただし,resizeやinsertなどでサイズ変更があった場合, サイズ変更前のポインタやイテレータが有効であることは保証されないので注意.

多次元配列

vectorで多次元配列を作成したい場合,以下のように定義する(2次元の場合).

vector< vector<int> > x;

定義時に容量を確保し,初期化したい場合は,

vector< vector<int> > x(n, vector<int>(n, 0));

上記の例ではn×nのサイズを確保し,0で初期化している. resize関数を用いる場合も同様で,

x.resize(n, vector<int>(n, 0));

となる.

使用する場合は普通の2次元配列と同様に

x[i][j]

として使用する.

erase,clear後のメモリサイズ

STLのコンテナでは,eraseやclear関数で要素を削除しても, 確保されたメモリはスコープを抜けるまでは確保されたままである. 例えば,以下のようなコードを実行すると,

vector<int> x;
x.resize(100);
for(int i = 0; i < 100; ++i) x[i] = i;

cout << x.capacity() << endl;
x.clear();
cout << x.capacity() << endl;

結果は,

100
100

となり,clearを実行した後もメモリが確保されたままであることが分かる. これを防ぐ方法としてswapを用いる方法と,shrink_to_fit関数を用いる方法がある. swapの場合は以下のようにする.

vector<int>(x).swap(x);

shrink_to_fitの場合は単純に

x.shrink_to_fit();

shrink_to_fitは環境によっては使えないかもしれないので注意(Visual Studio 2010では大丈夫).

試しに先ほどのコードに

x.shrink_to_fit();
cout << x.capacity() << endl;

と追記して実行してみると,

100
100
0

となる.


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2024-03-08 (金) 18:06:09