2013-05-23 14 views
12

私はoperator newを使用したプレースメント削除の結果に対してdeleteを呼び出していますか?

struct MyStruct { ~MyStruct() { } }; 

void *buffer = operator new(1024); 
MyStruct *p = new(buffer) MyStruct(); 
// ... 
delete p;  // <---------- is this okay? 

を行う場合は、~MyStruct()と同様にoperator deleteを呼び出す両方の世話をすることが保証deleteのですか?

+0

オブジェクトの割り当て方法と構築方法の違いは、1つのステップで処理するのと違うのですか?はいの場合、削除はおそらく失敗します。いいえの場合、削除はおそらく成功します。ですから、この標準がどのように 'delete'ではなく' new'の操作を指定するのかという疑問が生じます。 – nobar

+0

これをgcc + Valgrindでテストしました。エラーは報告されていませんでした。 – nobar

答えて

13

delete p

p->~MyStruct(); 
operator delete(p); 

に相当します。

[expr.delete]/2状態:

削除のオペランドの値が...前new式によって作成された非配列オブジェクトへのポインタかもしれません。

プレースメントnewは、new-expressionのタイプです。[expr.new]/1

new式
        :: オプト新しい新しい-配置オプト新しい型-IDの新しい初期化子オプト
        :: オプト新しい新しい-配置オプトタイプ-ID新しい初期化子

deleteがデストラクタの呼び出しになるように定義されオプトメモリの解放機能への呼び出しを行います。 [expr.delete]/6,7

...

オブジェクトのデストラクタを(もしあれば)呼び出します削除-表現 ... ... 削除-表現を解放関数を呼び出します。 ..

限り解放関数は、(それは、限り、あなたはあなたのクラスのoperator deleteをオーバーロードしていないようすべきである)、これはすべてが順調に定義されるべき割り当て機能と一致して。

+0

標準歩行+1! – Yakk

+2

Hmm。実装では、 'operator new'の戻り値の後にパディングを追加することはできません。 (そうではありません; C++ 11§5.3.4/ 10)それでも、私はまだこれについて不安を感じています。 'dynamic_cast ()'は、あなたが動的型を知らなくても、最も派生したポインタを取得するので、やむを得ないユースケースではないようです。 – Potatoswatter

+0

良い点Potatoswatter – GameDeveloper

12

[改訂]一般的にはOKではなく、deleteと一致するプレーンnewの式で取得したものだけです。それ以外の場合、割り当て解除関数が割り当て関数に一致することを保証するのはあなた次第です。したがって、元のoperator newがグローバル名前空間にあったと仮定すると、::delete p;を使用する方がより安全な一般的な解決方法になります。特に問題のクラス(またはその派生クラスの1つ)がoperator newをオーバーロードするときは、注意が必要です。

あなたは*pを作成するために配置-新しい表現を使っていると、「配置-delete式」のようなものが存在しないので、手動でオブジェクトを破棄して、メモリを解放する必要があるので:

あなたの例では、期待されるセマンティクスを明確に定義すべきであるので MyStructは、代替 operator deleteを持っていない限り、
p->~MyStruct(); 

operator delete(buffer); 
+3

ニージャークとは別に「これは奇妙で記憶に関連しているので、UBでなければなりません」と、あなたはこれに対してどのような証拠を持っていますか? – Mankarse

+0

@Mankarse: 'delete p'は' MyStruct :: operator delete'を呼び出す可能性があります。これは、 ':: operator delete'が実際に呼び出されたときに、何か完全に不適切なことが起きる可能性があります。 –

+0

真実ですが、単純な 'new'式で得られたものだけを**削除することはできません。 'MyStruct :: operator delete'が存在しないことを知っている状況でも動作します。 (ただし、これは 'delete'をいくらか安全ではなく、おそらくほとんどの状況で悪い考えにしていると私は同意します)。 – Mankarse

0

いいえ、一般的には削除を呼び出すべきではありません(場合によっては、削除されたオペレータの削除が大丈夫かもしれません)。

char *buffer = new char[1024]; 
MyStruct *p = new(buffer) MyStruct(); //placement new "i'm just calling constructor" 
p->~MyStruct(); //destroy the object. 

//delete p; // WHAT? even if you override operator delete it may be opaque to reader. 
delete [] buffer; // THIS DELETE IS OK (if you have first destroyed MyStruct) 
関連する問題