web-dev-qa-db-ja.com

スタックに割り当てられた変数でdeleteを呼び出す

プログラミングスタイルとデザインを無視して、スタックに割り当てられた変数でdeleteを呼び出すのは「安全」ですか?

例えば:

   int nAmount;
   delete &nAmount;

または

class sample
{
public:
    sample();
    ~sample() { delete &nAmount;}
    int nAmount;
}
54
unistudent

No 、スタックに割り当てられた変数でdeleteを呼び出すのは安全ではありません。 deleteによって作成されたものに対してのみnewを呼び出す必要があります。

  • mallocまたはcallocごとに、freeが1つだけ存在する必要があります。
  • newごとに、正確に1つのdeleteが必要です。
  • new[]は1つだけですdelete[]
  • スタックの割り当てごとに、明示的な解放または削除はありません。デストラクタは、必要に応じて自動的に呼び出されます。

一般に、これらのいずれかを組み合わせて使用​​することはできません。 free- ingまたはdelete[]-newオブジェクトの入力。これを行うと、未定義の動作が発生します。

98
Mr Fooz

さて、試してみましょう:

jeremy@jeremy-desktop:~$ echo 'main() { int a; delete &a; }' > test.cpp
jeremy@jeremy-desktop:~$ g++ -o test test.cpp
jeremy@jeremy-desktop:~$ ./test
Segmentation fault

どうやら安全ではないようです。

46
Jeremy Ruten

New(またはmalloc)を使用してメモリブロックを割り当てると、割り当てられた実際のメモリブロックは、要求したものよりも大きくなることに注意してください。メモリブロックには簿記情報も含まれているため、ブロックを解放すると、簡単に空きプールに戻され、場合によっては隣接する空きブロックと合体できます。

あなたが新しいから受け取っていないメモリを解放しようとすると、その簿記情報はそこにはありませんが、システムはそのように動作し、結果は予測不能です(通常は悪い)。

14
Ferruccio

はい、未定義の動作です:deleteから来なかったものをnewに渡すと、UBになります。

C++標準、セクション3.7.3.2.3:標準ライブラリで提供される割り当て解除関数の1つに提供される最初の引数の値は、nullポインタ値です。その場合、および割り当て解除関数が標準ライブラリで提供されるものである場合、割り当て解除関数の呼び出しは効果がありません。それ以外の場合、標準ライブラリのoperator delete(void*)に提供される値は、標準ライブラリのoperator new(std::size_t)またはoperator new(std::size_t, const std::nothrow_t&)の前回の呼び出しで返された値のいずれかです。

未定義の動作の結果は、未定義です。 「何も起こらない」ということは、他のことと同じくらい有効です。ただし、通常は「すぐには何も起こりません」:無効なメモリブロックの割り当てを解除すると、その後のアロケータの呼び出しで重大な結果が生じる可能性があります。

10
dasblinkenlight

Windowsでg ++ 4.4を少しプレイした後、非常に興味深い結果が得られました。

  1. スタック変数でdeleteを呼び出しても何も実行されないようです。エラーはスローされませんが、削除後に問題なく変数にアクセスできます。

  2. delete thisを持つメソッドを持つクラスがあると、オブジェクトがヒープに割り当てられている場合は正常に削除されますが、スタックに割り当てられている場合は削除されません(スタックにある場合は何も起こりません)。

7
Sambatyon

誰も何が起こるかわかりません。これは未定義の動作を呼び出すため、文字通り何でも起こります。 これをしないでください。

5
user529758

いいえ、newを使用して割り当てられたメモリはdelete演算子を使用して削除する必要があり、mallocを使用して割り当てられたメモリはfreeを使用して削除する必要があります。そして、スタックに割り当てられている変数の割り当てを解除する必要はありません。

4
Vinay

天使は翼を失います... deleteで割り当てられたポインターでのみnewを呼び出すことができます。そうでない場合、未定義の動作が発生します。

3
Luchian Grigore

ここではメモリはスタックを使用して割り当てられるため、外部から削除する必要はありませんが、動的に割り当てられている場合

int * a = new int()のような

メモリは空きストアから割り当てられるため、aを削除する必要があり、aを削除する必要はありません(それ自体はポインターです)。

1
Ashrith

あなたはすでに自分で質問に答えました。 deleteは、newを介して操作されるポインターにのみ使用する必要があります。それ以外のことは、単純で未定義の動作です。

したがって、実際に何が起こるかは言うまでもありません。正常に動作するコードからクラッシュしてハードドライブを消去するまでのすべてが、これを行うことの有効な結果です。 絶対にしないでください.

0
Grizzly

Newで動的に割り当てられていないアイテムでdeleteを呼び出してはならないため、これはUBです。とても簡単です。

0
Martin James