導入
C++で動的配列を扱う際、最も頻繁に使用されるのがstd::vectorです。しかし、何も考えずに要素を追加し続けると、内部でメモリの「再確保(リバッファリング)」が何度も発生し、パフォーマンスが低下する原因となります。今回紹介するstd::vector::reserveは、あらかじめ必要なメモリを確保しておくことで、この無駄な処理を省き、アプリケーションの実行速度を劇的に向上させるための重要なテクニックです。
基礎知識
std::vectorは、要素を追加する際に内部のメモリ領域がいっぱいになると、新しい大きな領域を確保し、既存のすべての要素を新しい領域へコピー(またはムーブ)してから古い領域を解放します。この「領域の確保・コピー・解放」というプロセスは非常にコストが高い処理です。
reserveメソッドを使うと、vectorに対して「将来的にこれくらいの要素数が必要になる」とあらかじめ伝えておくことができます。これにより、必要な容量を一度に確保できるため、追加のたびに発生するメモリ再確保の回数を最小限に抑えることが可能です。
実装/解決策
使い方は非常にシンプルです。要素を追加する前、あるいはvectorを生成した直後に、想定される最大要素数を引数に渡して呼び出すだけです。
ただし、重要な注意点として、reserveは「メモリを確保する」だけで、「要素数を増やす(サイズを変更する)」わけではないという点です。reserve後にアクセスできる要素数は0のままであり、実際のデータ追加にはpush_back等を使う必要があります。
サンプルプログラム
以下のコードは、reserveを使った場合と使わない場合の挙動のイメージを掴むための例です。
include
include
int main() {
// 1000個の要素を追加することがあらかじめ分かっている場合
std::vector
// 事前にメモリを確保しておく(再確保のコストを削減)
vec.reserve(1000);
// このループ内では、最初の数回を除いてメモリの再確保が発生しないため高速
for (int i = 0; i < 1000; ++i) {
vec.push_back(i);
}
std::cout << "現在のサイズ: " << vec.size() << std::endl;
std::cout << "確保済みの容量: " << vec.capacity() << std::endl;
return 0;
}
応用・注意点
現場で活用する際のポイントを2点挙げます。
1. capacityとsizeの違いに注意:
reserveはcapacity(確保済み容量)を増やしますが、size(現在の要素数)は増やしません。もし初期値も同時に設定したい場合は、reserveではなくコンストラクタでサイズを指定するか、std::vector::resizeを使用してください。
2. 過剰な確保はメモリ不足を招く:
「念のため」と非常に大きな値を確保しすぎると、実際に使用するメモリ量以上にメモリを消費してしまい、他の処理に悪影響を与える可能性があります。メモリ使用量とパフォーマンスのバランスを考慮し、適切な値を設定するようにしましょう。
メモリの断片化を避け、安定したパフォーマンスを実現するために、要素数が予測できる場合はぜひreserveを活用してみてください。

コメント