導入:なぜcapacityを知る必要があるのか?
C++で最もよく使われるコンテナといえばstd::vectorです。しかし、実は「要素数(size)」と「メモリ確保数(capacity)」が別物であることを意識している初心者は意外と多くありません。この違いを理解しないまま要素を追加し続けると、プログラムの裏側で何度もメモリの確保・コピーが発生し、パフォーマンスが低下する原因になります。今回は、vectorの裏側を支えるcapacityの仕組みについて解説します。
基礎知識:sizeとcapacityの違い
std::vectorは、内部で動的にメモリを確保する配列のようなものです。
sizeは「現在格納されている要素の数」を指します。
一方で、capacityは「メモリを再確保せずに格納できる最大要素数」を指します。
イメージとしては、sizeが「入っている荷物の数」、capacityが「箱全体の収容能力」です。箱がいっぱいになると、vectorは「新しい大きな箱」を準備して、古い箱から中身をすべてコピーして引っ越します。この「引っ越し(再確保)」は処理コストが高いため、可能な限り減らすのがプロのテクニックです。
実装:capacityを制御して効率化する
vectorの再確保を防ぐための強力な武器が reserve() 関数です。あらかじめ「これくらいの要素数になりそうだな」という予測がつく場合、reserve()を使ってcapacityを確保しておくことで、無駄な再確保処理をスキップできます。
サンプルプログラム
以下のコードを実行して、要素を追加した際にcapacityがどのように変化し、reserveによってどう改善されるかを確認してみましょう。
include <iostream>
include <vector>
int main() {
std::vector<int> v;
std::cout << "初期状態: size=" << v.size() << ", capacity=" << v.capacity() << std::endl;
// 要素を1つ追加
v.push_back(1);
std::cout << "1つ追加後: size=" << v.size() << ", capacity=" << v.capacity() << std::endl;
// あらかじめ容量を確保する(reserve)
// これにより、100個までメモリの再確保が発生しなくなる
v.reserve(100);
std::cout << "reserve(100)後: size=" << v.size() << ", capacity=" << v.capacity() << std::endl;
return 0;
}
応用・注意点:現場で役立つポイント
1. 再確保のルール: 実装によりますが、多くの環境ではcapacityが不足すると、現在の約1.5倍〜2倍の容量を新たに確保する仕様になっています。
2. メモリの無駄遣いに注意: reserve()で大きすぎる値を指定すると、使わないメモリを大量に確保することになり、メモリ不足の原因になります。必要な分だけ確保するのが鉄則です。
3. shrink_to_fit(): 逆に、要素を削除して容量が余ってしまった場合、shrink_to_fit() を呼ぶことで、使われていないメモリを開放してcapacityを現在のsizeに合わせることができます。
まずは、ループで大量のデータを追加する前に reserve() を呼ぶ癖をつけるだけで、プログラムの安定性と速度がぐっと向上しますよ!ぜひ試してみてください。

コメント