80

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

例えば:

   int nAmount;
   delete &nAmount;

また

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

12 に答える 12

130

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

  • mallocまたはごとcallocに、 が 1 つだけ存在する必要がありますfree
  • それぞれnewに が 1 つだけ存在する必要がありますdelete
  • それぞれnew[]に が 1 つだけ存在する必要がありますdelete[]
  • スタック割り当てごとに、明示的な解放や削除を行うべきではありません。デストラクタは、該当する場合、自動的に呼び出されます。

free一般に、これらのいずれも混合して一致さdelete[]せることはできませんnew。これを行うと、未定義の動作が発生します。

于 2009-01-14T03:44:51.737 に答える
57

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

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

したがって、どうやらそれはまったく安全ではありません。

于 2009-01-14T03:47:23.747 に答える
18

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

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

于 2009-01-14T05:11:47.677 に答える
11

はい、未定義の動作です: UBdeleteから来ていないものに渡す:new

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&)

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

于 2012-09-20T13:19:15.450 に答える
8

Windows で g++ 4.4 を少し試したところ、非常に興味深い結果が得られました。

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

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

于 2011-05-17T19:37:00.573 に答える
5

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

于 2012-09-20T13:18:56.750 に答える
4

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

于 2009-01-14T10:02:15.657 に答える
3

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

于 2012-09-20T13:19:03.360 に答える
1

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

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

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

于 2009-01-14T10:28:16.183 に答える
0

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

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

于 2012-09-20T13:19:46.573 に答える
0

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

于 2012-09-20T13:19:51.613 に答える