10

基本に戻りましょう。率直に言って、私はこれまでNewand Disposefunctions を使用したことがありません。しかし、New() のドキュメントと、 Embarcadero Technologiesの Web サイトにある例、および New() のDelphi Basics の説明を読んだ後、頭の中に疑問が残りました。

少量のメモリを節約System.New()する以外に、ローカル変数の代わりに使用する利点は何ですか?

の一般的なコード例New()は、多かれ少なかれ次のとおりです。

  var
      pCustRec : ^TCustomer;
  begin
      New(pCustRec);
      pCustRec^.Name := 'Her indoors';
      pCustRec^.Age  := 55;
      Dispose(pCustRec);
  end;

上記のコードが以下のコードよりも適切なのは、どのような状況ですか?

  var
      CustRec : TCustomer;
  begin
      CustRec.Name := 'Her indoors';
      CustRec.Age  := 55;
  end;
4

6 に答える 6

11

ローカル変数を使用できる場合は、使用してください。これは事実上例外のないルールです。これにより、最もクリーンで効率的なコードが得られます。

ヒープに割り当てる必要がある場合は、動的配列、GetMem または New を使用します。レコードを割り当てるときは New を使用します。

スタックを使用できない例には、コンパイル時にサイズがわからない構造体や非常に大きな構造体が含まれます。しかし、New の主な使用例であるレコードの場合、これらの懸念が当てはまることはめったにありません。

したがって、レコードのスタックとヒープの選択に直面した場合、常にスタックが正しい選択です。

于 2013-01-09T08:08:40.333 に答える
8

別の観点から:

どちらもバッファ オーバーフローの影響を受け、悪用される可能性があります

ローカル変数がオーバーフローすると、スタックが破損します。

ヒープ変数がオーバーフローすると、ヒープが破損します。

スタックの破損はヒープの破損よりも悪用されやすいと言う人もいますが、一般的にはそうではありません

オペレーティング システム、プロセッサ アーキテクチャ、ライブラリ、および言語には、この種の悪用を防ぐのに役立つさまざまなメカニズムがあることに注意してください。

たとえば、DEP ( Data Execution Prevention )、ASLR ( Address Space Layout Randomization ) などあります。

于 2013-01-09T07:31:58.323 に答える
7

ローカル静的変数は、限られたスタックにスペースを確保します。割り当てられたメモリは、基本的に利用可能なすべてのメモリであるヒープ上にあります。

前述のように、スタック スペースは限られているため、値によって渡される大きなローカル変数や大きなパラメーターを避ける必要があります (パラメーター宣言にvar/がない)。const

メモリ使用量について:
1. 単純な型 ( integercharstringなどdouble) はスタック上に直接配置されます。使用されるバイトの量は、sizeof(variable)関数によって決定できます。
2. レコード変数と配列についても同様です。3. ポインターとオブジェクトには 4/8 バイトが必要です。

于 2013-01-09T06:32:32.087 に答える
4

すべてのオブジェクト (つまり、クラス インスタンス) は常にヒープに割り当てられます。

値構造 (単純な数値型、それらの型のみを含むレコード) をヒープに割り当てることができます。

動的配列と文字列のコンテンツは、常にヒープに割り当てられます。スタック上に確保できるのは参照ポインタだけです。あなたが書く場合:

  function MyFunc;
  var s: string;
  ...

ここでは、4/8 バイトがスタックに割り当てられますが、文字列の内容 (テキスト文字) は常にヒープに割り当てられます。

したがって、New()/を使用してDispose()もあまり効果がありません。参照カウント型が含まれていない場合は、ゼロに設定する内部ポインターがないため、代わりにGetMem()/を使用できます。FreeMem()

New()orの主な欠点はDispose()、例外が発生した場合に...ブロックを使用する必要があることです。tryfinally

  var
    pCustRec : ^TCustomer;
  begin
    New(pCustRec);
    try
      pCustRec^.Name := 'Her indoors';
      pCustRec^.Age  := 55;
    finally
      Dispose(pCustRec);
    end;
  end;

スタックに割り当てると、コンパイラが隠れた方法でそれを行います。

  var
    CustRec : TCustomer;
  begin // here a try... is generated
    CustRec.Name := 'Her indoors';
    CustRec.Age  := 55;
  end;  // here a finally + CustRec cleaning is generated

New()そのため、私は/をほとんど使用せずDispose()、スタックに割り当てるか、クラス内で割り当てることをお勧めします。2

于 2013-01-09T07:10:36.687 に答える
2

ヒープ割り当ての通常のケースは、オブジェクトがそれを作成した関数よりも長く存続する必要がある場合です。

  1. 関数の結果として、またはvar/outパラメーターを介して、直接または何らかのコンテナーを返すことによって返されます。

  2. プロシージャ内で渡されるか、そうでなければアクセス可能なオブジェクト、構造体、またはコレクションに格納されています (これには、別のスレッドへのシグナル/キューイングが含まれます)。

于 2013-01-09T11:59:01.320 に答える
1

スタック領域が限られている場合は、ヒープからの割り当てを好むかもしれません。
参考文献

于 2013-01-09T06:28:14.733 に答える