トップC++入門 > vector
vector

1.vector

vectorはコンテナクラス[1]のひとつで、動的配列(可変長配列)クラスである。 文献[2]には最初に簡単な図があり、大変分かりやすい。


図1.vectorの構造(文献2より引用)


各要素は線形に、順序を保って格納される。配列と同じように、添え字によるランダムアクセスも高速である。 vectorは要素アクセスと末尾に対する追加・削除は高速である。しかし、 末尾以外に対する挿入・削除はdequeやlistより劣る[3]。

2.配列サイズの拡張

当初は、必要に応じて配列が自動的に拡張されると思っていたが、どうもそうではないようだ。 その都度、 サイズは、オブジェクト.resize(新サイズ) で、キャパシティは オブジェクト.reserve(新キャパシティ) で、 広げなければならないようだ。もちろん、オブジェクト.resize(新サイズ)でサイズを広げれば、 キャパシティもその分は広がる。reserveはもっと広げておきたいときだけ使う。

下にプログラム例を示す。

プログラム例

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> data = { 4, 6, 5 };

    data.resize(9);     // サイズ拡張が必須
    data[8] = 123;
    cout << "size: " << data.size() << endl;
    cout << "capacity: " << data.capacity() << endl;

    for (auto n : data) {
        cout << n << endl;
    }
}

このプログラムをコンパイル、実行した結果を下に示す。

c:\mh\www\cpp\src>cl /nologo /EHsc vector01.cpp
vector01.cpp

c:\mh\www\cpp\src>vector01
size: 9
capacity: 9
4
6
5
0
0
0
0
0
123

data.resize(9); なしで、 コンパイル、実行した結果を下に示す。

c:\mh\www\cpp\src>cl /nologo /EHsc vector01.cpp
vector01.cpp

c:\mh\www\cpp\src>vector01
size: 3
capacity: 3
4
6
5

このときは実行時エラーは起きなかった。 しかし、メモリ割り当て外のエリア data[8] にデータを書き込んでいるため、明らかに誤りである。

GNU の g++ でコンパイルしても結果は同じだった。

c:\mh\www\cpp\src>g++ vector01.cpp -std=c++1y

3.小さい数値の読み込み

この話題は vector ではなく、scanf関数に関するものであるが、たまたま同じプログラムで遭遇したので、 ここに記す。

次のプログラムは 0 〜 255 の数値を unsigned char 型の動的配列に scanf関数で読み込もうとしたものである。 %d に対応する引数は int 型変数のアドレスでなければならないので、次のプログラムは誤りである。

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<unsigned char> data(10);
    
    data[0] = data[1] = 255;
    data[5] = data[6] = data[7] = data[8] = data[9] = 255;
    sscanf("123,255,34", "%d,%d,%d", &data[2], &data[3], &data[4]); 
    for (int n : data) {
        cout << n << endl;
    }
}

コンパイル・実行結果を下に示す。 &data[2], &data[3], &data[4] はそれぞれ int型(4バイト) 変数のアドレスと解釈して、 順に 4 バイト(上位3バイトは 0 )のデータが書き込まれる。 この順で実行されたため、最終的には data[4] で書き込んだ4バイト中上位の3バイト (元のデータは 255)が 0 に書き変えられる。

後の3バイトが壊されたのはこのパソコンのアーキテクチャがリトルエンディアンのためである。 ビッグエンディアンの場合には、前の3バイトが壊される。

したがって、一旦、int型変数 small に読み込んで data[n] = (unsigned char)small; とするなどの対応が必要である。このとき data[n] = small; でもいいが、 上位バイトが無視されることを承知していることを明らかにするため、自分は、キャストを付けることを習慣にしている。

c:\mh\www\cpp\src>cl /nologo /EHsc vector02.cpp
vector02.cpp

c:\mh\www\cpp\src>vector02
255
255
123
255
34
0
0
0
255
255

A.リファレンス

[1] C++ コンテナ クラス入門
[2] C++ 動的配列クラス std::vector 入門
[3] vector