次のコードスニペットを検討してください。
#include <vector>
using namespace std;
void sub(vector<int>& vec) {
vec.Push_back(5);
}
int main() {
vector<int> vec(4,0);
sub(vec);
return 0;
}
「vec」に「sub」関数の5を格納するスペースが残っていないと仮定すると、新しいメモリはどこに割り当てられますか?
サブ機能のスタックフレームに?その場合、サブ関数の最後に5が削除されます。しかし、サブ関数のスタックフレームはその時点でスタックの一番上にあるため、メイン関数のスタックフレームは拡大できません。
std :: vectorはヒープ上の要素にメモリを割り当てますか?しかし、そのヒープメモリをどのように解放するのでしょうか。スタック上のローカルベクトルの場合、削除されることをベクトルに通知せずに、ベクトルを含む関数のスタックフレームが最後に削除されますか?
Std :: vectorはヒープ上の要素にメモリを割り当てますか?
はい。または、より正確には、構築時に渡したアロケータに基づいて割り当てます。指定しなかったため、デフォルトのアロケーターを取得します。デフォルトでは、これは ヒープ になります。
しかし、そのヒープメモリをどのように解放するのでしょうか。
destructor を介して、スコープから外れた場合。 (範囲外のベクトルへのpointerはデストラクタをトリガーしないことに注意してください)。しかし、値によってsub
に渡した場合は、新しいコピーを作成(および後で破棄)します。 5はそのコピーにプッシュバックされ、コピーはクリーンアップされ、main
のベクターは変更されません。
STLのすべてのコンテナーはテンプレート引数でパラメーター化されます。通常、最後の引数はA
またはAllocator
と呼ばれ、デフォルトはstd::allocator<...>
です。ここで、...
は値のタイプを表しますコンテナ内に保管されます。
Allocator
は、メモリを提供し、このメモリ領域の要素を構築/破棄するために使用されるクラスです。メモリは、アロケータを作成したプールから、またはヒープから直接割り当てることができます。デフォルトでは、std::allocator<T>
は::operator new
の単純なラッパーであるため、推測したとおりにヒープにメモリを割り当てます。
メモリはオンデマンドで割り当てられ、少なくともvector
のデストラクタが呼び出されたときに割り当て解除されます。 C++ 11はshrink_to_fit
を導入して、メモリをより早く解放します。最後に、ベクターが現在の容量を超えると、新しい(より大きな)割り当てが行われ、オブジェクトがそれに移動し、古い割り当てが解放されます。
すべてのローカル変数と同様に、デストラクタは、宣言されたスコープの最後に実行されると呼び出されます。したがって、関数が終了する前に、ベクトルデストラクタが呼び出され、その後で初めてスタックが縮小され、制御が呼び出し元に戻ります。
また、ベクター(vec
)はオブジェクト自体であることにも注意してください。それはスタックに常駐し、このオブジェクトがスコープ外になると(これはmain
の終わりです)、破壊されます。要素のメモリは、このオブジェクトの初期化中に割り当てられ、その破棄とともに解放されます。これは、要素のリソース管理が関連付けられているため、 [〜#〜] raii [〜#〜] イディオムの素敵な例ですベクトルオブジェクトの寿命に。
ヒープ内のベクトルのアドレスをsubに指定したため、ヒープに割り当てられます。スペースが残っていない場合は、例外がスローされます。