C++ の動的メモリ割り当てとキーワードについて学んでおり、new
言及new[]
されています。ソースコードで固定サイズの変数や配列を単純に宣言するのとは異なり、実行時にユーザーがメモリ割り当てのサイズを指定できるようになると言われています。
この概念がわかりません。それはどのように機能しますか?アイデアを明確にする必要があるだけで、例が役立つでしょう!
C++ の動的メモリ割り当てとキーワードについて学んでおり、new
言及new[]
されています。ソースコードで固定サイズの変数や配列を単純に宣言するのとは異なり、実行時にユーザーがメモリ割り当てのサイズを指定できるようになると言われています。
この概念がわかりません。それはどのように機能しますか?アイデアを明確にする必要があるだけで、例が役立つでしょう!
したがって、10 個の整数の配列が必要な場合は、次のように記述します。
int arr[10];
しかし、このようなことをしたい場合はどうでしょう。
cout << "How many?";
cin >> num;
int arr[num];
まあ、C++ 言語はそれを許しません。代わりに、次のことを行う必要があります。
int *arr = new int[num];
配列を作成します。そして後であなたは[1]使用しなければなりません:
delete [] arr;
メモリを解放します。
それで、これはどのように機能しますか?num
new を呼び出すと、C++ ランタイム ライブラリ (C++ の基礎を構成する、ユーザーが記述する必要のないコード) は、整数が占めるスペースの量を把握し、そのためのメモリ内のスペースを見つけます。「記憶を見つける方法」については詳しく説明しません。今のところ、私を信じてください。いくつかの整数を格納するために使用できるメモリがどこかに利用可能です。
後で を呼び出すdelete
と、同じメモリが元のメモリの「プール」または「ヒープ」に戻されます。
もちろん、たとえば 256 MB のメモリを搭載したマシンがあり、2 億 5000 万の整数を格納するためのスペースを要求しようとすると、整数が 1 バイト以上を占めることを念頭に置いて、うまくいきません -ここには「魔法」はありません-メモリは依然としてマシンで利用可能な量に制限されています....実行中にプログラムで必要なメモリ量を決定する権利があります。プログラムを書くときに決定します。
編集:一般的に、この目的に役立つ既存の「コンテナ」および「ラッパークラス」を使用して、メモリ割り当てを「非表示」にすることをお勧めします。例えば:
std::vector<int> arr;
整数の可変ストレージとして機能し、メモリを解放することについて心配する必要はありません。また、メモリをそこに格納する前に必要な数を知ることさえありません。
std::shared_ptr<int> arr = new int[num];
別のケースでは、「shared_ptr」が使用されなくなった場合 [共有ポインター クラス内でそれを追跡するため、メモリの解放を気にする必要はありません]。
[1] メモリ リークをしたくない場合、およびメモリ リークを行うのは「悪いスタイル」です。あなたがそうしても誰も幸せにしません。
C++ でのメモリ割り当て、「new operator」と「operator new」に関する質問、new int(100)
vsnew int[100]
に関する質問、メモリの初期化に関する質問など、多くの投稿を見てきました。 、そしてこの要約を書くためにこの質問を選んでいます。これは、動的メモリ割り当て、つまり実行時のヒープへの割り当てに関するものです。また、概要の実装(パブリック ドメイン)も提供します。
動的メモリ割り当ての主な機能:
<cstdlib>
) では、主にmalloc
とcalloc
とがありfree
ます。については話しませんrealloc
。<new>
) では、次のように
なります。new T( args )
new (std::nothrow) T( args )
delete ( T* )
new T[ size_t ]
new (std::nothrow) T[ size_t ]
delete[] ( T* )
new (void*) T( args )
new (void*) T[ size_t ]
::operator new( size_t )
。::operator new( size_t, std::nothrow )
。::operator new( size_t, ptr )
。簡潔な比較については、この投稿をご覧ください。
主なポイント: 完全な型消去 (void*
ポインター)、したがって構築/破棄なし、バイト単位で指定されたサイズ (通常は を使用sizeof
)。
malloc( size_t )
メモリをまったく初期化しません(生メモリにはゴミが含まれているため、使用前に常に手動で初期化してください)。calloc( size_t, size_t )
すべてのビットを 0 に初期化します (わずかなオーバーヘッドですが、POD 数値型に役立ちます)。割り当てられたメモリは、ONLYを使用して解放する必要があります。free
クラス インスタンスの構築/破棄は、使用前/メモリ解放前に手動で行う必要があります。
主なポイント: 類似した構文が異なることを行うため、混乱を招きます。すべての delete
ステートメントはデストラクタを呼び出します。すべての delete
ステートメントは完全に型指定されたポインターを受け取ります。一部の new
ステートメントは完全に型指定されたポインターを返します。一部の new
ステートメントはコンストラクターを呼び出します。
警告: 以下に示すように、キーワードまたは関数new
のいずれかになり。混乱を避けるために、「new operator」および/または「operator new」については話さないことが最善です。関数またはキーワードのいずれかを含む有効なステートメントを「ステートメント」と呼びます人々は「 -expressions」についても話しで はキーワードであり、関数ではありません。new
new
new
new
これを自分で使用しないでください。これはnew-expressionsによって内部的に使用されます (以下を参照)。
::operator new( size_t )
::operator new( size_t, std::nothrow )
サイズをバイト単位で取得し、成功した場合は a を返しますvoid*
。std::bad_alloc
、後者は を返しますNULL
。::operator new( sizeof(T) )
の単一T
のオブジェクト(およびdelete
リリース) と::operator new( n*sizeof(T) )
、複数のオブジェクト (およびリリース) に使用しdelete[]
ます。これらの割り当てはメモリを初期化しません。特に、割り当てられたオブジェクトのデフォルト コンストラクターを呼び出しません。したがって、またはを使用して割り当てを解放する前に、すべての要素を手動で初期化する必要があります。delete
delete[]
注:これを自分で使用しないでください。ただし、それを使用する必要がある場合は、またはそのような割り当てvoid
を呼び出すときに、型付きポインターの代わりに私は個人的に、一部のコンパイラで POD 以外の型で実行時エラーを経験しました (私のミスかもしれません)。delete
delete[]
これを自分で使用しないでください。これはnew-expressionsによって内部的に使用されます (以下を参照)。void *ptr = ::operator new( n*sizeof(T) )
以下では、いくつかのタイプT
とサイズを想定していますn
。
次に、デフォルトのコンストラクターを使用して開始する型の要素を::operator new( n*sizeof(T), (T*) ptr )
初期化します。ここでは割り当てはなく、default-constructor を使用した初期化のみです。n
T
ptr
T::T()
new T( args )
constructor を使用して、型の単一オブジェクトのメモリを割り当てて初期化します。デフォルトのコンストラクターは、引数が省略されない限り呼び出されません (つまり、 または さえも)。失敗時に例外をスローします。T
T::T( args )
new T()
new T
std::bad_alloc
new (std::nothrow) T( args )
戻る以外は同じです。NULL
delete
デストラクタを呼び出し、T::~T()
対応するメモリを解放するために使用します。new T[n]
デフォルトのコンストラクターを使用して、型のオブジェクトにメモリを割り当てて初期化します。失敗時に例外をスローします。n
T
std::bad_alloc
new (std::nothrow) T[n]
戻ることを除いて、同上。NULL
delete[]
のデストラクタを呼び出し、対応するメモリを解放するために使用します。T::~T()
ここでは割り当てはありません。割り当てがどのように行われたかに関係なく、次のようになります。
new (ptr) T(args)
T::T(args)
に格納されているメモリのコンストラクタを呼び出しますptr
。引数が省略されない限り、デフォルトのコンストラクターは呼び出されません。new (ptr) T[n]
from to に格納された型(つまり、bytes)のオブジェクトのデフォルト コンストラクタT::T()
を呼び出します。n
T
ptr
ptr+n
n*sizeof(T)