さて、私はC ++プログラミングに非常に慣れていないので、これに対する決定的な答えを数日間探していました。ヒープとスタックでメンバー変数を宣言する必要があるのはいつですか?私が見つけた答えのほとんどは他の問題を扱っていますが、メンバー変数にヒープを使用するのが最適な場合と、メンバーをスタックするのではなくヒープする方がよい理由を知りたいです。
5 に答える
最初に把握する必要のある2つの重要な概念があります。
「ヒープ」と「スタック」の観点から考えることは避けてください。これらは、言語ではなく、コンパイラ/プラットフォームの実装の詳細です。1 代わりに、オブジェクトの存続期間の観点から考えてください。オブジェクトの存続期間は、その「親」の存続期間に対応する必要がありますか、それとも長持ちする必要がありますか?後者が必要な場合は、
new
(直接的または間接的に)を使用してオブジェクトを動的に割り当てる必要があります。メンバー変数の有効期間は常に親と同じです。メンバー変数はポインターである可能性があり、それが指すオブジェクトは独立した存続期間を持つ可能性があります。ただし、ポイントされたオブジェクトはメンバー変数ではありません。
しかし、あなたの質問に対する一般的な答えはありません。大まかに言えば、正当な理由がない限り、動的に割り当てないでください。上で示唆したように、これらの理由は通常、寿命がその「親」と異なる必要がある状況に対応します。
1.実際、C ++標準は、「ヒープ」と「スタック」について実際には話していません。これらは、パフォーマンスを最適化するとき、または一般的に考えるときに考慮することが重要ですが、プログラム機能の観点からはほとんど関係ありません。
メンバー変数は、クラス自体のメンバーです。それらはヒープにもスタックにもありません。むしろ、クラス自体がどこにある場合でもあります。
レベルの間接参照を追加し、ヒープにメンバーを個別に割り当てる理由はほとんどありません。ポリモーフィズム(メンバーのタイプが常に同じであるとは限らない場合)がはるかに一般的です。
いくつかの用語をまっすぐにするために:あなたが何と呼び、オブジェクトの寿命を説明するheap
か。stack
1つ目は、存続期間がであることを意味しdynamic
、2つ目とautomatic
3つ目(言及していません)はstatic
です。
通常dynamic
、オブジェクトが作成されたスコープよりも長持ちする必要がある場合は、オブジェクトの存続期間が必要になります。別の一般的なケースは、異なる親オブジェクト間でオブジェクトを共有する場合です。また、動的なライフタイムは、オブジェクト指向のデザイン(多くのポリモーフィズムを使用し、値を使用しない)で作業する場合にも必要ですQt
。
動的な存続期間を必要とするイディオムは、pimpl-イディオムです。
ほとんどのジェネリックプログラミングライブラリは、値と値のセマンティクスに重点を置いているため、動的バインディングをあまり使用せず、自動有効期間がはるかに一般的になります。
より実装固有の理由で動的割り当てが必要な例もいくつかあります。
- 動的にサイズ設定されたオブジェクト(コンテナ)
- 不完全な型の処理(pimpl-idiomを参照)
- タイプの簡単なnull可能性
これらはすべて一般的なガイドラインであり、ケースバイケースで決定する必要があります。一般に、動的オブジェクトよりも自動オブジェクトを優先します。
スタックはを参照しcall stack
ます。関数呼び出し、リターンアドレス、パラメーター、およびローカル変数は、呼び出しスタックに保持されます。パラメータを渡すか、ローカル変数を作成するときは常に、スタックメモリを使用します。スタックには一時ストレージのみがあります。現在の関数がスコープ外になると、パラメーターの変数にアクセスできなくなります。
ヒープは、動的割り当てに使用されるメモリの大きなプールです。演算子を使用してnew
メモリを割り当てる場合、このメモリはヒープから割り当てられます。現在の関数が終了した後(スコープを失った後)に失いたくないオブジェクトを作成するときに、ヒープメモリを割り当てたいと考えています。delete
オブジェクトは、スペースがまたはで割り当て解除されるまでヒープに格納されますfree()
。
この例を考えてみましょう
。クラスノードのフィールドメンバーヘッドを持つリンクリストを実装します。
各ノードにはフィールドメンバーがありnext
ます。ノード*ではなくノードタイプのこのメンバーの場合、すべてのノードのサイズは、チェーン内のノードの後のノードの数によって異なります。
たとえば、リストに100個のノードがある場合、ヘッドメンバーは巨大になります。次のノードを内部に保持するため、それを保持するのに十分なサイズが必要であり、nextは次のノードを保持します。したがって、ヘッドには、次の98などの99ノードを保持するのに十分なスペースが必要です...これ
を避けたいので、この場合、次のノード自体ではなく、各ノードの次のノードへのポインタを使用することをお勧めします。 。