プログラミングスタイルと設計を無視して、スタックに割り当てられた変数で削除を呼び出すのは「安全」ですか?
例えば:
int nAmount;
delete &nAmount;
また
class sample
{
public:
sample();
~sample() { delete &nAmount;}
int nAmount;
}
プログラミングスタイルと設計を無視して、スタックに割り当てられた変数で削除を呼び出すのは「安全」ですか?
例えば:
int nAmount;
delete &nAmount;
また
class sample
{
public:
sample();
~sample() { delete &nAmount;}
int nAmount;
}
いいえdelete
、スタック割り当て変数を呼び出すのは安全ではありません。delete
によって作成されたものだけを呼び出す必要がありますnew
。
malloc
またはごとcalloc
に、 が 1 つだけ存在する必要がありますfree
。 new
に が 1 つだけ存在する必要がありますdelete
。 new[]
に が 1 つだけ存在する必要がありますdelete[]
。 free
一般に、これらのいずれも混合して一致さdelete[]
せることはできませんnew
。これを行うと、未定義の動作が発生します。
さて、試してみましょう:
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
したがって、どうやらそれはまったく安全ではありません。
new (または malloc ) を使用してメモリ ブロックを割り当てる場合、割り当てられる実際のメモリ ブロックは、要求したものよりも大きくなることに注意してください。メモリ ブロックにはいくつかの簿記情報も含まれているため、ブロックを解放すると、簡単に空きプールに戻して、隣接する空きブロックと合体させることができます。
new から受け取っていないメモリを解放しようとすると、その簿記情報はそこにありませんが、システムはそのように動作し、結果は予測不能になります (通常は悪いことです)。
はい、未定義の動作です: 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&)
定義されていない動作の結果は、まあ、定義されていません。「何も起こらない」ことは、他の何よりも有効な結果です。ただし、通常は「すぐには何も起こりません」: 無効なメモリ ブロックの割り当てを解除すると、その後のアロケータの呼び出しで深刻な結果が生じる可能性があります。
Windows で g++ 4.4 を少し試したところ、非常に興味深い結果が得られました。
スタック変数で delete を呼び出しても、何もしないようです。エラーはスローされませんが、削除後は問題なく変数にアクセスできます。
メソッドを持つクラスを持つとdelete this
、オブジェクトがヒープに割り当てられている場合はオブジェクトが正常に削除されますが、スタックに割り当てられている場合は削除されません (スタックにある場合は何も起こりません)。
何が起こるかは誰にもわかりません。これは未定義の動作を引き起こすため、文字通り何でも起こり得ます。これをしないでください。
いいえ、new を使用して割り当てられたメモリは delete 演算子を使用して削除し、malloc を使用して割り当てられたメモリは free を使用して削除する必要があります。また、スタックに割り当てられている変数の割り当てを解除する必要はありません。
天使は翼を失います...delete
で割り当てられたポインターのみを呼び出すことができnew
ます。そうしないと、未定義の動作が発生します。
ここでは、メモリはスタックを使用して割り当てられるため、外部で削除する必要はありませんが、動的に allcoted した場合
int *a=new int() のように
次に、メモリがフリーストアから割り当てられるため、&a を削除せずに a を削除する必要があります (a 自体はポインターです)。
あなたはすでに自分で質問に答えました。delete
を通じて取得されたポインターにのみ使用する必要がありますnew
。それ以外のことを行うことは、単純で単純な未定義の動作です。
したがって、実際に何が起こるかはわかりません。コードが正常に機能することから、クラッシュしてハードドライブを消去することまで、これを行うことの有効な結果です。絶対にしないでください。
newで動的に割り当てられていないアイテムでdeleteを呼び出してはならないため、UBです。それはとても簡単です。