10

私の知る限り、newオペレーターは次のことを行います: (間違っていたら訂正してください。)

  1. メモリを割り当て、割り当てられたメモリの最初のブロックの参照を返します。(メモリは明らかにヒープから割り当てられます。)
  2. オブジェクトを初期化します (コンストラクターを呼び出します)。

また、演算子new[]は、配列内のすべての要素に対してこれを行うことを除いて、同様の方法で機能します。

これらの演算子の両方が C++ と Java でどのように異なるか教えてください。

  1. 彼らのライフサイクルの観点から。
  2. メモリの割り当てに失敗した場合はどうなりますか。
4

5 に答える 5

2

Java の詳細についてはわかりませんが、C++ では次のようにnewなります。new[]

  1. メモリを割り当てる

    new Tまたは式がある場合new T(args)、コンパイラは、メモリを取得するために呼び出す関数を決定します。

    • Tに適切なメンバーがある場合、そのメンバーoperator newが呼び出されます
    • それ以外の場合、ユーザーが適切なグローバルoperator newを提供した場合、そのグローバルが呼び出されます。

      要求されたメモリを割り当てることができない場合operator newは、 で設定できる新しいハンドラ関数が呼び出されますset_new_handler。その関数は、割り当てが成功するようにいくらかのスペースを解放するか、プログラムを終了するか、型の例外またはそれstd::bad_allocから派生した例外をスローする可能性があります。デフォルトの new ハンドラーは単にstd::bad_alloc.

      メモリ割り当てのために呼び出されるnew T[n]以外の場合も同じことが起こります。operator new[]

  2. オブジェクトを作成します。新しく割り当てられたメモリ内のオブジェクト。

    オブジェクトのnew T(args)対応するコンストラクターが呼び出されます。operator deleteコンストラクターが例外をスローした場合、対応する( と同じ場所にありますoperator new)を呼び出すことにより、メモリの割り当てが解除されます。

    POD (つまり、組み込み型または基本的に C の構造体/共用体)new Tであるかどうかによって異なります。TT が POD の場合は何も起こらず、そうでない場合は のように扱われnew T()ます。

    かどうかにnew T[n]も依存しTますPOD。繰り返しますが、POD は初期化されません。非 POD の場合、デフォルトのコンストラクターが順番に各オブジェクトに対して呼び出されます。1 つのオブジェクトのデフォルト コンストラクターがスローした場合、それ以上のコンストラクターは呼び出されませんが、既に構築されているオブジェクト (コンストラクターがスローしたばかりのオブジェクトは含まれません) は逆の順序で破棄されます (つまり、デストラクタが呼び出されます)。次に、メモリは適切な .xml で割り当て解除されますoperator delete[]

  3. 新しく作成されたオブジェクトへのポインターを返します。new[]ポインターは、割り当てられたメモリの先頭を指していない可能性が高いことに注意してください。これは、構築されたオブジェクトの前に割り当てられたオブジェクトの数に関する情報が存在する可能性があるためです。これは、破棄するオブジェクトの数delete[]を把握するために使用されます。

delete ptrいずれの場合も、オブジェクトは( normal で割り当てられたオブジェクトの場合new) またはdelete[] ptr( array で作成されたオブジェクトの場合)で破棄されるまで存続しますnew T[n]。サード パーティのライブラリを追加しない限り、C++ にはガベージ コレクションはありません。

operator newand をoperator delete直接呼び出して生メモリを割り当てることもできることに注意してください。operator new[]とについても同様ですoperator delete[]。ただし、これらの低レベル関数の場合でも、呼び出しを混在させることはできないことに注意してください。たとえば、 で割り当てたメモリの割り当てを解除operator deleteするなどですoperator new[]

いわゆるplacement newを使用して、割り当てられたメモリ内のオブジェクトを(どのように取得したかに関係なく)copnstructすることもできます。これは、生メモリへのポインタを への引数として与えることによって行われnewますnew(pMem) T(args)。このような明示的に構築されたオブジェクトを破棄するには、オブジェクトのデストラクタを直接呼び出すことができますp->~T()

operator new配置 newは、ポインタを追加の引数として取り、それを返すだけのan を呼び出すことによって機能します。この同じメカニズムを使用して、operator new対応する追加の引数を取るオーバーロードに他の情報を提供することもできます。ただし、対応する を定義することはできますがoperator delete、それらは構築中にオブジェクトが例外をスローしたときのクリーンアップにのみ使用されます。「プレースメントの削除」構文はありません。

C++ によって既に提供されている配置の新しい構文のもう 1 つの使用法は、新しいものではありません。これは追加のパラメーターを取り、割り当てが失敗した場合に null ポインターを返すという点でのみ、std::nothrow通常と異なります。new

newまた、C++ の唯一のメモリ管理メカニズムではないことに注意してください。一方では、C 関数mallocとがありfreeます。通常はoperator newoperator new[]呼び出すだけですがmalloc、これは保証されません。したがって、これらの形式を混在させることはできません (たとえば、 でfree割り当てられたメモリを指すポインタを呼び出すことによってoperator new)。一方、STL コンテナーは、オブジェクトの割り当て/割り当て解除、およびコンテナー内のオブジェクトの構築/破棄を管理するオブジェクトであるアロケーターを通じて割り当てを処理します。

そして最後に、ライフタイムが言語によって直接制御されるオブジェクト、つまり静的ライフタイムと自動ライフタイムのオブジェクトがあります。自動有効期間オブジェクトは、ローカル スコープで型の変数を定義するだけで割り当てられます。それらは、実行がその行を通過すると自動的に作成され、実行がスコープを離れると自動的に破棄されます (スコープが例外によって残されることを含みます)。静的有効期間オブジェクトは、キーワード static を使用して、グローバル/名前空間スコープまたはローカル スコープで定義されます。これらは、プログラムの起動時 (グローバル/名前空間スコープ) または定義行が実行されるとき (ローカル スコープ) に作成され、プログラムの最後まで存続し、構築の逆順で自動的に破棄されます。

一般に、自動変数または静的変数は、動的割り当て (newつまり、アロケーターで割り当てるすべてのもの) よりも優先されます。これは、独自に行う必要がある動的割り当てとは異なり、コンパイラーが適切な破棄を処理するためです。オブジェクトを動的に割り当てた場合、同じ理由で自動/静的オブジェクト (コンテナー、スマート ポインター) によってその有効期間を管理することが望ましいです。

于 2013-06-09T22:47:51.473 に答える