2013-07-02 7 views
14

私の質問は、私のコードのコメントに配置されていますメモリ割り当てと0サイズ:メモリリークを取得できますか?

int* a = new int[0];// I've expected the nullptr according to my logic... 
bool is_nullptr = !a; // I got 'false' 
delete[] a; // Will I get the memory leaks, if I comment this row? 

ありがとうございました。

+0

なぜあなたは '0'バイトを割り当てますか? – Kolyunya

+3

@Kolyunya通常は誰もいませんが、サイズがゼロの変数であればどうなりますか? –

+0

@JoachimPileborgあなたの要点を詳しく教えてください。私はまだそれを取得できません。質問は私にとっては非常に面白いです。 'malloc(0)'を呼び出すと、後で 'free'と呼ぶでしょうか?メモリは割り当てられていますか? – Kolyunya

答えて

16
C++ 11について

、所与コード:

int* a = new int[0]; 

ゼロ5.3.4/7に従って、リーガルサイズである:

場合に式の値noptr-new-declaratorが0の場合、割り当て関数が呼び出されて に要素を持たない配列を割り当てます。

起動オペレータが18.6.1.2(強調鉱山)の通りである:

ボイド*オペレータ新しい[](スタンダード:: size_tのサイズ)。

...

3必要な行動:new演算子(STD :: size_t型)と同じ。この要件は、この機能の代替バージョンである を拘束しています。

4デフォルトの動作:演算子new(size)を返します。 null以外適切に整列するポインタストレージ(3.7.4)、または他のスローを返します:18.6.1.1 ...

void* operator new(std::size_t size); 

3必要な行動を参照

... bad_- alloc例外です。この要件は、この関数の置き換えバージョンをバインドしています。

したがって、返されるポインタはnullでなくてはなりません。

それ以降はdelete[]にする必要があります。

+0

Bjarne Stroustrupが私に答えました:operator newは常にオブジェクトへのポインタを返します(メモリが枯渇した場合bad_allocをスローします)。あなたが新しいもののために削除を使用しない場合、あなたはリークを取得します。リークされるメモリの正確な量は実装固有のもので、たぶん2,3ワードです。 –

+4

@ブッシュ:まあ、正直言って、私はあなたがすでに話されていた何かであなたの時間を取ったのはちょっと悲しいですが、そこにはあります.... –

+1

いいえ私は答えがマークされた後B. Stroustrup "答え"として。 –

4

はい、deleteがないとメモリリークが発生します。

すべてnewは、deleteとペアにする必要があります。プログラマ割り当てサイズが0であっても、アロケータはアライメント要件、管理オーバーヘッドなどのために、要求されたメモリより多くのメモリを割り当てることがあります。この場合

+0

どのようにメモリリークですか?どのくらいのメモリが漏れますか? – Kolyunya

+3

@ Kolyunya私はそれがメモリアロケータに任されていると思います。 –

+0

また、アロケータは 'new int [0]'要求ごとに新しいポインタを返す必要があり、これらのポインタはすべての割り当てにわたって一意でなければなりません。いくつかの 'new'の後に' delete'が続かないと、ポインタが足りなくなることが明らかです – user4815162342

4

それは、 実装はあなたがnullptrかどうかを返されますが、 あなたはこのポインタデリファレンスまた、メモリリークが発生しますdeleteを呼び出していないしていないように注意する必要があるかどうかを定義しています。

W.r.t deleteを呼び出すルールは単純です:
"あなたが呼び出す場合newあなたがdeleteを呼び出す必要があります。"

修正:他の回答で引用は明らかにしてきたように
、それはあなたのnullptrを返すことができません。

+0

この例で 'delete'を呼び出さないとどうなりますか?どのくらいのメモリが漏れますか? – Kolyunya

+1

@Kolyunya:割り当てられたメモリ(*実装に依存する*)があれば、 'delete'を呼び出さなければ、リークします。確かにそれは非ゼロになることだけです。 –

+0

あなたが '0'バイトを割り当てても削除するものはないと思っていました...ありがとうございました。 – Kolyunya

7

はい、リークがあり、実装に依存しません。

この新しい式では、NULLポインタを生成できません。 operator new[]を呼び出すことによってメモリを割り当てます。これは、適切に整列された記憶域にnull以外のポインタを戻すか、またはbad_alloc例外をスローするために必要です(C++ 11§18.6.1.1/ 3および§18.6.1.2/ 3を参照) 。さらに、割り当て機能要求(§3.7.4.1)は、割り当て関数への各呼び出しが、割り当てられているがまだ割り当て解除されていない他のすべてのポインタとは異なるポインタを返すことを必要とする。従って、実装は、単にそれが常に返す単一の "空の割り当て"ポインタを持つことはできません。

エクステントがゼロの場合でも、すべての配列形式の新しい式はの何かを割り当てます。 delete[]経由でそのオブジェクトの割り当てを解除しないと、そのオブジェクトが漏洩しています。

10

C++ 03 new int[0]は、[]の値が厳密に正の値でなければならないため、結果として未定義の結果になります。ゼロは良い(5.3.4/6 "新規")。後でメモリリークがあるかどうかを尋ねることは意味がないことです。

C++で11 new int[0]は、長さ0の配列(5.3.4/7 "New")を割り当てるためのアロケータを呼び出します。割り振り要求が成功すると、ポインタが返されます。要求されたサイズ以上でなければならないことを除いて、そのポインタが指し示すブロックのメモリ量を示す標準はありません。しかし、少なくとも1つの文字を割り当てることの効果は少なくともあります。なぜなら、解放されるまで、そのアドレスはアロケータによって再度返されることができないからです。実際には、簿記のオーバーヘッドは複数の文字になります。

+1

ああ;私はC++ 03とC++ 11の違いについて知らなかった。とても興味深い。 C++ 03には、「_new-expression_は配列の最初の要素**(もしあれば)**へのポインタを生成します」という言語が含まれています。これをC++ 11で読むと、このテキストはカウントがゼロであるケースを処理すると仮定していましたが、C++ 03に存在するため、非投げのフォームがnullを返すケースを処理することも考えられます? –

+4

C++ 03に関するコメントはまったく間違っています。 C++で03 (§5.3.4/ 6): "直接新宣言子の式は で、負でない数値の の整数または列挙型(3.9.1)でなければなりません。 0は負でない値です。 (実際には、 はC++ 98以降では変更されていません) –

+1

"すべての定数式* ...は厳密に正の値に評価されます" - 標準についての強調 - '5 *(* constant * expression *)は正でなければならず(コンパイル時に評価される)' 'new float [n] [5]'のようなコードであり、 )は非負でなければなりません(実行時に評価されます) – anatolyg