std::vector
読み:エスティーディー-ベクター
外語:std::vector
標準C++ライブラリのうちSTLに含まれる、ベクター要素を扱うためのクラス。配列と同様の機能を提供する。
概要
mallocやnewと同様、配列の連続要素に相当する領域をヒープに確保する。領域は動的に確保され、自動的に解放をしてくれる。
クラスは、ベクター要素に対するアクセスの他、追加や削除といった処理を提供する。
書式
#include <vector>
特徴
利点
mallocやnewと違い自動的に開放されるため、メモリーリークが起こらない。
メモリーの連続性
C++ Standard Library Defect Report Listの第69項として、std::vectorのメモリー連続性について触れられている。
69. Must elements of a vector be contiguous?
Discussion:
The issue is this: Must the elements of a vector be in contiguous memory?
Proposed resolution:
Add the following text to the end of 23.3.6 [vector], paragraph 1.
The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
簡単に訳すと、次のようになる。
69. ベクター要素は連続している必要があるか?
議論:
問題はこれです: ベクター要素は、連続したメモリー内に存在する必要があるか?
決議案:
23.3.6 [ベクター] 第1項の末尾に、次の文を追加する。
ベクター要素は、vがvector<T, Allocator>で、何らかの型Tがbool以外の場合、0 <= n < v.size()の全てにおいて等式&v[n] == &v[0] + nに従うことを意味し、連続的に格納される。
これによれば、「現在の」std::vectorにはメモリーの連続性はあると解釈できる。古い実装では連続していないかもしれないが、そのような古すぎる実装は無視するならば、連続性を理由にmallocやnewなどを使う理由はもはや無い。
必要なだけstd::vectorでメモリーを確保すれば、それは&v[0]から連続したメモリー領域として扱うことができる。メモリーリークに怯える必要は、もはや無いのである。
処理時間
ベクター要素へのアクセスと要素の追加は、定数時間(大きさに限らず常に一定時間)で完了する。
特定の値の検出、ベクターへの要素挿入は、線形時間(入力の大きさに比例する時間)を要する。
ブール型のvector
ビット値であるboolのvector、つまりvector<bool>は、標準C++ライブラリでは特殊化して処理している。
複数のビットがパックして処理されることもあり(処理系依存)、メモリー効率がよいこともある。
vector<bool>は、ビットを反転するメソッドとしてflip();が追加され、また演算子=がbool値を参照するようにオーバーロードされる。
仕様
コンストラクター
文法は次の通り。
vector();
vector(size_type size);
vector(size_type num, const TYPE &val);
vector(const vector &from);
vector(input_iterator start, input_iterator end);
上から順に、次のようにベクターは作られる。
- 引数なし ‐ 空のベクターを作る
- size ‐ 大きさsizeのベクターを作る
- numと&val ‐ num個のvalの複製をベクターに入れる
- &from ‐ fromと同じ内容のベクターを作る
- startとend ‐ startからendまでの要素を持ったベクターを作る
演算子
文法は次の通り。
v1 == v2
v1 != v2
v1 <= v2
v1 >= v2
v1 < v2
v1 > v2
v[]
各ベクターは、比較演算子によって比較できる。
各ベクターの個々の要素は[]演算子によって調べられる。先頭へのポインターが必要なら&v[0]で求められるが、C++11では、この目的のために新たにdata()というメソッドが追加された。
メソッド
assign() | ベクターに要素を割り当てる |
at() | 指定した位置の要素を返す |
back() | 最終要素への参照を返す |
begin() | 先頭を指すイテレーターを返す |
capacity() | ベクターが保持できる要素数を返す |
clear() | 全ての要素を削除する |
empty() | ベクターが空ならtrueを返す |
end() | 末尾の次を指すイテレーターを返す |
erase() | 要素を削除する |
flip() | ビットを反転する (vector<bool>のみ) |
front() | 先頭要素への参照を返す |
get_allocator() | ベクターのアロケーターを返す |
insert() | 要素をベクターに挿入する |
max_size() | ベクターが保持できる最大要素数を返す |
pop_back() | 最終要素を削除する |
push_back() | ベクターの末尾に要素を追加する |
rbegin() | ベクター末尾を指すリバースイテレーターを返す |
rend() | ベクター先頭を指すリバースイテレーターを返す |
reserve() | ベクターが保持できる要素数を設定する |
resize() | ベクターのサイズを変更する |
size() | ベクター中の要素数を返す |
swap() | 二つのベクターを入れ替える |
応用方法
C++で、オプション文字列をUTF-8のstring型として扱う方法。
〓や〓といった、シフトJISで表わせないものをファイル名としてオプションに渡す場合はUnicodeとしてオプションを受け取る必要があるが、Windows標準のUTF-16、つまりwchar_tでは処理が面倒なだけで何の利点もない。
そこで、普段はUTF-8にして内部で持ち回し、必要な時には再びUTF-16にしてAPIを呼べばよいのである。
CHogeAppクラスのアプリケーションと想定して説明する。
#include <vector>
#include <string>
上の他に、必要なヘッダーファイルは逐一includeする(<windows.h>など)。
#ifdef _MSC_VER
int wmain(int argc, wchar_t *argv[])
{
std::vector<std::string> args(argc);
for (int idx = 0; idx < argc; ++idx)
{
int nLen = WideCharToMultiByte(CP_UTF8, 0, argv[idx], wcslen(argv[idx]), NULL, 0, NULL, NULL);
std::vector<char> buf(nLen + 1);
nLen = WideCharToMultiByte(CP_UTF8, 0, argv[idx], wcslen(argv[idx]), &buf[0], nLen, NULL, NULL);
args[idx] = &buf[0];
}
CHogeApp theApp(argc, args);
return (int)0;
}
#else
int main(const int argc, const char *argv[])
{
std::vector<std::string> args(argc);
for (int idx = 0; idx < argc; ++idx)
{
args[idx] = argv[idx];
}
CHogeApp theApp(argc, args);
return EXIT_SUCCESS;
}
#endif
まず必要なmain関数は上記の通りである。Windowsではwmain関数でUTF-16形式のオプション文字列が得られる。UNIX(BSDやLinux等)はいい加減なので、UTF-8環境であればそのままUTF-8の文字列がchar *で得られるため、それをそのままstd::stringに代入する。
CHogeApp::CHogeApp(const int argc, const std::vector<std::string> &args)
{
Main(argc, args);
}
CHogeApp::~CHogeApp()
{
}
コンストラクターとデストラクターは必要に応じて内容を書き換える。主処理はCHogeApp::Mainとする。
void CHogeApp::Main(const int argc, const std::vector<std::string> &args)
{
...
}
Main関数以降に必要な処理を書けばよい。この時点で、argcの他に、std::string型の引数が得られている。
std::vectorなので、手動でのメモリー解放は不要。また、参照はargs[0]のように、char *型の時と変わらない。先頭アドレスが欲しいときは&args[idx][0]のようにする。
再検索