【C++学習|実務向け】std::vector::clear() の正しい理解とメモリ管理の勘所

導入

C++のstd::vectorを使用する際、最も頻繁に呼び出されるメソッドの一つがclear()です。しかし、実務において「要素を消したつもり」でメモリ管理を誤り、パフォーマンス低下やメモリリークを招くケースは少なくありません。本記事では、clear()が内部で何を行い、キャパシティ(capacity)とどのように付き合うべきかを解説します。

基礎知識

std::vectorは動的配列であり、内部に「要素数(size)」と「確保済み領域(capacity)」という2つの概念を持っています。

・size(): 現在保持している有効な要素の数。
・capacity(): 再確保なしで格納できる最大要素数。

std::vector::clear()を呼び出すと、すべての要素のデストラクタが順に呼び出され、sizeは0になります。重要なのは、clear()を呼んでもcapacityは減少しないという点です。これは、再利用を想定してメモリの再確保(malloc/free相当の重い処理)を避けるための設計です。

実装/解決策

clear()後のメモリを完全に解放したい場合は、std::vector::shrink_to_fit()を併用するか、一時的なvectorとのswap(いわゆるスワップ・トリック)を行う必要があります。しかし、頻繁に要素を出し入れするループ内であれば、あえてclear()だけを行い、メモリを使い回す方が高速です。

サンプルプログラム

include
include

int main() {
std::vector vec = {1, 2, 3, 4, 5};

std::cout << "初期状態: size=" << vec.size() << ", capacity=" << vec.capacity() << std::endl; // clear()を実行 vec.clear(); // sizeは0になるが、capacityは維持される std::cout << "clear後: size=" << vec.size() << ", capacity=" << vec.capacity() << std::endl; // メモリを完全に解放したい場合(C++11以降) vec.shrink_to_fit(); std::cout << "shrink_to_fit後: size=" << vec.size() << ", capacity=" << vec.capacity() << std::endl; return 0; }

応用・注意点

実務で注意すべき点は以下の3つです。

1. オブジェクトの破棄: vectorがポインタを保持している場合、clear()を呼んでもポインタ先の実体は解放されません。スマートポインタ(std::unique_ptrなど)を使用するか、clear()前に手動でメモリを解放する処理が必要です。
2. 再利用の判断: ループのたびにclear()して再push_backする場合、capacityが十分に確保されていれば、メモリ確保のオーバーヘッドをゼロにできます。安易にshrink_to_fit()を呼ぶと、逆にパフォーマンスが悪化する可能性があります。
3. 例外安全性: 要素のデストラクタで例外が投げられることは稀ですが、デストラクタ内で例外が発生した場合、vectorの状態が不整合になる可能性があることを頭の片隅に置いておきましょう。

基本的には「capacityを維持したいか、解放したいか」という目的を明確にして使い分けるのが、熟練したC++エンジニアの流儀です。

コメント

タイトルとURLをコピーしました