はじめに
C++の std::vector
は、要素を追加 (push_back
) していくと、内部のメモリ領域(キャパシティ)が足りなくなった時点で、より大きな新しいメモリ領域を確保し、そこに全要素をコピーするという「メモリの再確保」を自動で行います。
この再確保は便利な反面、大量の要素を追加するループの中などで頻繁に発生すると、コピーのコストが積み重なり、パフォーマンスの低下を招きます。
もし、プログラムの実行前に「最終的に、少なくともこれくらいの要素数が必要になる」ということが分かっている場合、.reserve()
メソッドを使って、あらかじめ十分なメモリ領域を確保しておくことができます。これにより、ループ中のメモリ再確保を未然に防ぎ、処理を大幅に高速化することが可能です。
reserve()
を使ったサンプルコード
このコードは、.reserve()
を使って事前にメモリを確保した場合と、使わなかった場合の capacity()
の変化を比較します。
完成コード
#include <iostream>
#include <vector>
using namespace std;
int main() {
// --- reserve() を使う場合 ---
cout << "--- reserve() を使う場合 ---" << endl;
vector<int> vec_with_reserve;
// 1. 少なくとも1000個の要素が入るメモリを事前に確保
vec_with_reserve.reserve(1000);
cout << "確保後の capacity: " << vec_with_reserve.capacity() << endl;
cout << "現在の要素数 (size): " << vec_with_reserve.size() << endl;
// 1000個の要素を追加しても、メモリ再確保は発生しない
for (int i = 0; i < 1000; ++i) {
vec_with_reserve.push_back(i);
}
cout << "1000個追加後の capacity: " << vec_with_reserve.capacity() << endl;
cout << "1000個追加後の size: " << vec_with_reserve.size() << endl;
cout << "\n--- reserve() を使わない場合 ---" << endl;
// --- reserve() を使わない場合 ---
vector<int> vec_without_reserve;
cout << "初期 capacity: " << vec_without_reserve.capacity() << endl;
// 1000個の要素を追加する過程で、複数回のメモリ再確保が発生する
for (int i = 0; i < 1000; ++i) {
vec_without_reserve.push_back(i);
}
cout << "1000個追加後の capacity: " << vec_without_reserve.capacity() << endl;
return 0;
}
コードの解説
vec_with_reserve.reserve(1000);
これが、メモリを事前確保する核心部分です。
.reserve(n)
:vector
のキャパシティ(.capacity()
が返す値)が、少なくともn
以上になるようにメモリを確保します。- もし、呼び出し時点のキャパシティが既に
n
以上であれば、何も起こりません。 reserve()
を呼び出しても、vector
の要素数 (.size()
) は一切変わりません。ただ、将来の要素追加に備えて、内部のメモリ領域だけを拡張します。
パフォーマンスへの影響
reserve()
を使わなかった vec_without_reserve
の場合、1000回の push_back
の間に、capacity
が 0 -> 1 -> 2 -> 4 -> 8 -> ...
のように、何度も拡張(再確保とコピー)されていきます。
一方、vec_with_reserve
では、最初に 1000
以上のキャパシティを確保しているため、ループの中では一度も再確保が発生せず、単純な要素の追加だけが実行されます。要素数が非常に多い場合、この差はプログラム全体の実行時間に大きな影響を与えます。
まとめ
今回は、C++の vector
(および string
)のパフォーマンスを向上させる .reserve()
メソッドについて解説しました。
.reserve(n)
を使うと、少なくともn
個の要素を格納できるメモリを事前に一括で確保できる。- これにより、ループ処理などでの断続的なメモリ再確保を防ぎ、処理を高速化できる。
.reserve()
は要素数 (.size()
) を変更するものではない。
プログラムのロジック上、最終的な要素数がある程度予測できる場合には、reserve()
を積極的に活用することで、より効率的なコードを書くことができます。