5

C++ の動的メモリ割り当てとキーワードについて学んでおり、new言及new[]されています。ソースコードで固定サイズの変数や配列を単純に宣言するのとは異なり、実行時にユーザーがメモリ割り当てのサイズを指定できるようになると言われています。

この概念がわかりません。それはどのように機能しますか?アイデアを明確にする必要があるだけで、例が役立つでしょう!

4

2 に答える 2

10

したがって、10 個の整数の配列が必要な場合は、次のように記述します。

int arr[10]; 

しかし、このようなことをしたい場合はどうでしょう。

cout << "How many?";
cin >> num;

int arr[num];

まあ、C++ 言語はそれを許しません。代わりに、次のことを行う必要があります。

int *arr = new int[num]; 

配列を作成します。そして後であなたは[1]使用しなければなりません:

delete [] arr; 

メモリを解放します。

それで、これはどのように機能しますか?numnew を呼び出すと、C++ ランタイム ライブラリ (C++ の基礎を構成する、ユーザーが記述する必要のないコード) は、整数が占めるスペースの量を把握し、そのためのメモリ内のスペースを見つけます。「記憶を見つける方法」については詳しく説明しません。今のところ、私を信じてください。いくつかの整数を格納するために使用できるメモリがどこかに利用可能です。

後で を呼び出すdeleteと、同じメモリが元のメモリの「プール」または「ヒープ」に戻されます。

もちろん、たとえば 256 MB のメモリを搭載したマシンがあり、2 億 5000 万の整数を格納するためのスペースを要求しようとすると、整数が 1 バイト以上を占めることを念頭に置いて、うまくいきません -ここには「魔法」はありません-メモリは依然としてマシンで利用可能な量に制限されています....実行中にプログラムで必要なメモリ量を決定する権利があります。プログラムを書くときに決定します。

編集:一般的に、この目的に役立つ既存の「コンテナ」および「ラッパークラス」を使用して、メモリ割り当てを「非表示」にすることをお勧めします。例えば:

 std::vector<int> arr;

整数の可変ストレージとして機能し、メモリを解放することについて心配する必要はありません。また、メモリをそこに格納する前に必要な数を知ることさえありません。

 std::shared_ptr<int> arr = new int[num]; 

別のケースでは、「shared_ptr」が使用されなくなった場合 [共有ポインター クラス内でそれを追跡するため、メモリの解放を気にする必要はありません]。

[1] メモリ リークをしたくない場合、およびメモリ リークを行うのは「悪いスタイル」です。あなたがそうしても誰も幸せにしません。

于 2013-01-29T02:25:25.797 に答える
5

C++ でのメモリ割り当て、「new operator」と「operator new」に関する質問、new int(100)vsnew int[100]に関する質問、メモリの初期化に関する質問など、多くの投稿を見てきました。 、そしてこの要約を書くためにこの質問を選んでいます。これは、動的メモリ割り当て、つまり実行時のヒープへの割り当てに関するものです。また、概要の実装(パブリック ドメイン)も提供します。


C と C++

動的メモリ割り当ての主な機能:

  • C (ヘッダー<cstdlib>) では、主にmalloccallocとがありfreeます。については話しませんrealloc
  • C++ (ヘッダー<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 ]
    • 内部new 式:
      • 生メモリの割り当て::operator new( size_t )
      • 例外のない生メモリの割り当て::operator new( size_t, std::nothrow )
      • 割り当てなしの生メモリの初期化::operator new( size_t, ptr )

簡潔な比較については、この投稿をご覧ください。


レガシー C 動的割り当て

主なポイント: 完全な型消去 (void*ポインター)、したがって構築/破棄なし、バイト単位で指定されたサイズ (通常は を使用sizeof)。

malloc( size_t )メモリをまったく初期化しません(生メモリにはゴミが含まれているため、使用前に常に手動で初期化してください)。calloc( size_t, size_t )すべてのビットを 0 に初期化します (わずかなオーバーヘッドですが、POD 数値型に役立ちます)。割り当てられたメモリは、ONLYを使用して解放する必要があります。free

クラス インスタンスの構築/破棄は、使用/メモリ解放前に手動で行う必要があります。


C++ 動的割り当て

主なポイント: 類似した構文が異なることを行うため、混乱を招きます。すべての deleteステートメントはデストラクタを呼び出します。すべての deleteステートメントは完全に型指定されたポインターを受け取ります。一部の newステートメントは完全に型指定されたポインターを返します。一部の newステートメントはコンストラクターを呼び出します

警告: 以下に示すように、キーワードまたは関数newのいずれかになり。混乱を避けるために、「new operator」および/または「operator new」については話さないことが最善です。関数またはキーワードのいずれかを含む有効なステートメントを「ステートメント」と呼びます人々は「 -expressions」についても話しで はキーワードであり、関数ではありません。newnewnewnew

Raw メモリの割り当て (初期化なし)

これを自分で使用しないでください。これは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[]ます。

これらの割り当てはメモリを初期化しません。特に、割り当てられたオブジェクトのデフォルト コンストラクターを呼び出しません。したがって、またはを使用して割り当てを解放する前に、すべての要素を手動で初期化する必要があります。deletedelete[]

:これを自分で使用しないでください。ただし、それを使用する必要がある場合は、またはそのような割り当てvoidを呼び出すときに、型付きポインターの代わりに私は個人的に、一部のコンパイラで POD 以外の型で実行時エラーを経験しました (私のミスかもしれません)。deletedelete[]

Raw メモリの初期化 (割り当てなし)

これを自分で使用しないでください。これはnew-expressionsによって内部的に使用されます (以下を参照)。void *ptr = ::operator new( n*sizeof(T) )以下では、いくつかのタイプTとサイズを想定していますn

次に、デフォルトのコンストラクターを使用して開始する型の要素を::operator new( n*sizeof(T), (T*) ptr )初期化します。ここでは割り当てはなく、default-constructor を使用した初期化のみです。nTptrT::T()

単一オブジェクトの割り当てと初期化

  • new T( args )constructor を使用して、型の単一オブジェクトのメモリを割り当て初期化します。デフォルトのコンストラクターは、引数が省略されない限り呼び出されません (つまり、 または さえも)。失敗時に例外をスローします。TT::T( args )new T()new Tstd::bad_alloc
  • 失敗した場合にnew (std::nothrow) T( args )戻る以外は同じです。NULL
  • deleteデストラクタを呼び出し、T::~T()対応するメモリを解放するために使用します。

複数オブジェクトの割り当てと初期化

  • new T[n]デフォルトのコンストラクターを使用して、型のオブジェクトにメモリを割り当てて初期化します。失敗時に例外をスローします。nTstd::bad_alloc
  • 失敗した場合にnew (std::nothrow) T[n]戻ることを除いて、同上。NULL
  • 各要素delete[]のデストラクタを呼び出し、対応するメモリを解放するために使用します。T::~T()

メモリの初期化 (別名「placement new」)

ここでは割り当てはありません。割り当てがどのように行われたかに関係なく、次のようになります。

  • new (ptr) T(args)T::T(args)に格納されているメモリのコンストラクタを呼び出しますptr。引数が省略されない限り、デフォルトのコンストラクターは呼び出されません。
  • new (ptr) T[n]from to に格納された型(つまり、bytes)のオブジェクトのデフォルト コンストラクタT::T()を呼び出します。nTptrptr+nn*sizeof(T)

関連記事

于 2014-12-24T01:03:12.100 に答える