C++プログラミング言語では、newとdeleteは動的メモリ割り当て、オブジェクト構築、オブジェクト破棄を実行する一対の言語構成要素です。[ 1 ]
「配置 new」と呼ばれる形式を除き、この演算子はプロセスのヒープnew上のメモリ割り当て要求を表します。十分なメモリが利用可能な場合、必要に応じてオブジェクトコンストラクタを呼び出し、メモリを初期化し、新しく割り当てられ初期化されたメモリのアドレスを返します。[ 2 ] [ 3 ]最も単純な形式の新しい要求は次のようになります。new
T * p = new T ; T * p = new T (); // プリミティブをゼロ初期化しますここで、 は型のポインタ(または、のスーパークラスなど、ポインタを割り当てることができる他の型)pです。のデフォルト コンストラクタが存在する場合は、それが呼び出されて、割り当てられたメモリ バッファにインスタンスが構築されます。TTTTT
型のオブジェクトに必要なメモリが空き領域に十分に確保されていない場合T、要求は型の例外newをスローして失敗を示します。これにより、割り当ての結果を明示的にチェックする必要がなくなります。std::bad_alloc
の解放対応はnewでありdelete、これはまず引数に対してデストラクタ(存在する場合)を呼び出し、次に によって割り当てられたメモリをnewフリー ストアに戻します。 へのすべての呼び出しはnewへの呼び出しと対応付けられなければなりませんdelete。そうしないとメモリ リークが発生します。[ 1 ]
新しい構文には、メモリ割り当てとオブジェクト構築をより細かく制御できるいくつかのバリアントがあります。デフォルトのコンストラクタとは異なるコンストラクタを呼び出し、引数を渡すには、関数呼び出しのような構文を使用します。
T * p = new T (引数);T新しく割り当てられたバッファを初期化する際に、デフォルトコンストラクタではなく、引数1つのコンストラクタを呼び出します。
別のバリアントでは、 単一のオブジェクトではなく、オブジェクトの配列を割り当てて初期化します。
T * p = new T [ N ];Nこれは、型のオブジェクトの連続した配列を格納するのに十分な大きさのメモリバッファを空き領域から要求しT、配列の各要素に対してデフォルトコンストラクタを呼び出します。
で割り当てられたメモリは、ではなく演算子new[]を使用して解放する必要があります。不適切な形式を使用すると、未定義の動作が発生します。C++コンパイラは、誤った形式を使用した場合に診断メッセージを生成する義務はありません。delete[]delete
C ++11規格では追加の構文が規定されています。
constexpr size_t N = /* 何らかの長さ */ ;T * p = new T [ N ] { initializer1 , ..., initializerN };各p[ i ]を初期化子i +1に初期化します。
JavaとC#newには、クラスコンストラクタを呼び出す演算子がありますが、演算子はありません。Javaにはデストラクタがdeleteありません。C#にはデストラクタがありますが、ほとんど使用されず、演算子を介して呼び出すことはできません。delete
public class Person { private String name ; private int age ;public Person ( String name , int age ) { this.name = name ; this.age = age ; } }Person p = new Person ( "Alice" , 30 );Rustにはオブジェクト指向スタイルのコンストラクタはありませんが、構造体をインスタンス化するためのファクトリメソッドに名前を付ける慣習がありnew(通常はを返しますSelf)、手動削除はを実装することによって行われますstd::ops::Drop。[ 4 ]
JavaScriptとTypeScriptには、演算子newとがありますdelete。ただし、はnewクラスのコンストラクタを呼び出すために使用されますが、deleteはデストラクタを呼び出しません(JavaScriptやTypeScriptにはデストラクタが存在しないため)。代わりに、はdeleteオブジェクトからプロパティを削除します。
class User { name : string ; age? : number ; // 削除を許可するためオプションとしてマークされていますconstructor ( name : string , age ?: number ) { this.name = name ; this.age = age ; } }let user : User = new User ( "Alice" , 30 );ユーザー.年齢を削除します。// TypeScriptエラーなし// 出力: { name: "Alice" } console.log ( user ) ;C++では、deleteデフォルトコンストラクタなどのコンパイラ生成メソッドを無効にするためにも使用されます。C ++26では、削除理由を指定できるようになりました。
class NonCopyable { public : NonCopyable () = default ; NonCopyable ( const NonCopyable & ) = delete ( "コピーコンストラクタなし" ); NonCopyable & operator = ( const NonCopyable & ) = delete ( "コピー代入なし" ); };メモリ割り当て要求を処理するのに十分なメモリが見つからない場合new、エラーは 3 つの方法で報告されます。まず、ISO C++ 標準では、new_handlerプログラムがC++ランタイムにカスタム関数を登録することを許可しています。登録されている場合、newエラーが発生するたびにこの関数が呼び出されます。は、new_handlerより多くのメモリを利用可能にしようと試みるか、それができない場合はプログラムを終了させます。
がインストールされていない場合はnew_handler、new代わりに型の例外std::bad_allocがスローされます。したがって、プログラムはC言語の慣習のように、返されたポインタの値をチェックする必要はありません。例外がスローされなかった場合、割り当ては成功します。
3つ目のエラー処理方法は、バリアント形式によって提供されますnew(std::nothrow)。この形式では、例外をスローしないことを指定します。代わりに、割り当てエラーを通知するためにヌルポインタが返されます。
演算子をオーバーロードするnewことで、特定の型(クラス)がインスタンスに対して独自のメモリ割り当てアルゴリズムを使用できるようになります。例えば、以下はシングルトンパターンのバリエーションで、最初の呼び出しでインスタンスが割り当てられ、以降のすべての呼び出しで同じインスタンスが返されます。new Singleton()
import std ;class Singleton { private : static void * instance = nullptr ; static size_t refcount = 0 ; public : static void * operator new ( size_t size ) { if ( ! instance ) { instance = std :: malloc ( size ); } ++ refcount ; return instance ; }static void operator delete ([[ maybe_unused ]] void * p ) noexcept { if ( -- refcount == 0 ) { std :: free ( instance ); instance = nullptr ; } } };この機能はC++の歴史の初期から利用可能でしたが、具体的なオーバーロードメカニズムは変更されました。オブジェクト指向のnewC++プログラムは、内部的にCのアロケータを使用する` malloc`を使用して多数の小さなオブジェクトを割り当てる傾向があったため、この機能が言語に追加されました( §malloc とfreeの関係を参照)。しかし、これは典型的なCプログラムが行うより少なく大きな割り当てに最適化されていました。Stroustrupは、初期のアプリケーションでは、C関数がmalloc()「実際のシステムで最も一般的なパフォーマンスのボトルネック」であり、プログラムが最大50%の時間をこの関数に費やしていたと報告しました。[ 5 ]
標準 C++ はC 標準ライブラリを包含しているため、C の動的メモリ割り当てルーチンmalloc()、、calloc()およびrealloc()もfree()C++ プログラマーが利用できます。これらのルーチンはオブジェクトの初期化と破棄を行わないため、ほとんどの場合、使用は推奨されません。[ 6 ]newおよびdeleteは、実際には、手動でのオブジェクト初期化の必要性を回避するために、C++ の最初のバージョン (当時は「クラス付き C」と呼ばれていました) で導入されました。[ 5 ]
C言語のルーチンでは、割り当てられた配列を で拡張または縮小できますがrealloc()、 で割り当てられたメモリ バッファのサイズを変更することはできませんnew[]。代わりに、 C++標準ライブラリでは、std::vectorテンプレート クラスで拡張または縮小できる動的配列(コレクション)が提供されています。
C++ 標準ではnew/deleteと C のメモリ割り当てルーチンの間に関係は規定されていませんが、newと は通常、とdeleteのラッパーとして実装されます。[ 7 ] 2 つの操作ファミリーを混在させると、たとえば、割り当てられたメモリを -ing したり、割り当てられたメモリを -ing したりすると、未定義の動作が発生し、実際にはロックの解放失敗によるデッドロックなど、さまざまな致命的な結果につながる可能性があります。[ 8 ]malloc()free()free()newdeletemalloc()
{{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)