push_back() で登録

Vector コンテナに push_back() で cell(データ)を登録します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. 前回作成した Vector コンテナ入門 をベースにして、 Vector コンテナに push_back() で cell(データ)を登録してみましょう。
    Vector は配列と同じように cell(要素)を添え字で参照するので、領域が連続していなければなりません。
    これをどのようにプログラムするかが、今回の最大のポイントです。
  2. Vector をテストする Main Program(VectorTest.cpp)です。
    "Vector.h" をインクルードします。
    Vector<int> v; でサイズを指定しないで Vector Class を定義します。
    サイズを省略するとコンストラクタを見れば解るように iterator を作るため cell が一個確保されるだけです。
    v.push_back(i) で、9~0の順に10件のデータを登録しています。
    v.at(i) メンバー関数で登録されたデータを印字します。
    v.capacity() はメモリ上に割り当てられた cell の個数で、v.size() は実際に使用されているサイズです。
    push_back() で登録すると v のキャパシティーとサイズが増えることを確認して下さい。
    /*★ Main Program  Step2    前田  稔 ★*/
    #include <iostream>
    #include "Vector.h"
    using namespace std;
    
    void main()
    {   int i;
        Vector<int> v;
    
        // 逆順に格納する
        for(i=9; i>=0; i--) v.push_back(i);
        // 表示
        cout << "v  ";
        for(i=0; i<v.size(); i++)   cout << v.at(i) << "  ";
        cout << endl;
        // 添え字で参照する
        cout << "v[0]=" << v[0] << "  v[4]=" << v[4] << "  v[9]=" << v[9] << endl;
        cout << "キャパシティー= " << v.capacity() << "  サイズ= " << v.size() << endl;
    }
    
  3. template を使って Vector Class を定義した Vector.h ファイルです。
    前回作成した Vector Class をベースにして、拡張して行きます。
    cell(データ)をインデックスで参照する at() 関数では、領域外をアクセスしないようにチェックしています。
    void push_back(const T &x) が今回のメインテーマとなる関数の宣言です。
    private で void resize(int size) が宣言されていますが、push_back() から呼び出される関数です。
    /*★ Vector Class Step2    前田  稔 ★*/
    //※ 省略されている部分は前回作成した Vector Class を参照して下さい
    { public:
        typedef T* iterator;
        typedef T& reference;
    
        iterator begin()  { return array; }
        iterator end()    { return array+current_size; }
        int  size()       { return current_size; }
        int  capacity()   { return array_size; }
    
        // at関数はoperator[]と異なり、チェックつき
        reference at(int index)
        {   if( size() <= index )
            {   cerr << "error" << endl;
                exit(1);
            }
            return array[index];
        }
    
        void push_back(const T  &x);
    
      private:
        void resize(int size);
        iterator array;
        int current_size;
        int array_size;
    
    };
    
  4. Vector.h ファイルの続きで、今回のメインテーマの push_back() です。
    template を使った Object Class の基礎は Template Object Class を参照して下さい。
    current_size と array_size を比べてデータが追加出来るかを調べます。
    追加する余地が無ければ「size() + 10」をパラメータにして resize() を呼び出します。
    array[current_size] に追加されたデータを格納して current_size をインクリメントします。
    template<class T> void Vector<T>::push_back(const T &x)
    {   if(current_size >= array_size)  resize( size() + 10 );
        array[current_size+1] = array[current_size];
        array[current_size]   = x;
        current_size++;
    }
    
  5. Vector.h ファイルの続きで resize() です。
    メインテーマとして push_back() を紹介しましたが、実際にはこちらがメインです。
    resize() ではデータ領域をパラメータで渡されたサイズ(size)に拡張(縮小)します。
    Vector は配列と同じように cell(要素)を添え字で参照するので、領域が連続していなければなりません。
    そこで、新しく new T[size+1] で領域を確保して、現在のデータをコピーします。
    古い領域を削除して、新しい領域を array に設定します。
    array_size を設定し直して完了です。
    このことからも解るように、あらかじめサイズが解っているときはコンストラクタでサイズを指定する方が賢明です。
    push_back() を繰り返すと余分な時間がかかります。
    // 配列の大きさをcurrent_size+1に変える
    template<class T> void Vector<T>::resize(int size)
    {   iterator tmp  = new T[size+1];
        iterator tmp2 = tmp;
        iterator itr  = begin();
        for(; itr!=end(); itr++,tmp++)  *tmp = *itr;
        delete [] array;
        array = tmp2;
        array_size = size;
    }
    
    #endif
    

【演習】

乱数で発生した25件のデータを push_back() で登録して、at() メンバー関数を使って表示して下さい。
このときのキャパシティーとサイズも確認して下さい。

超初心者のプログラム入門(C/C++)