5

配置deleteで割り当てられたポインタを呼び出すことはできますか?いいえの場合、なぜですか?詳しく説明してください。new

プレースメントの削除がないことを知っています。しかし、なぜポインタを削除するだけでは、ポインタが指すメモリがどのように割り当てられているかを気にせずにメモリを削除できないのでしょうか。

delete2つのことをしています:

  1. destrucorを呼び出す
  2. メモリを解放します

そして、新しい配置によって作成されたオブジェクトに対して、これら2つの操作のいずれも呼び出せないという削除の理由はわかりません。理由について何か考えはありますか?

4

5 に答える 5

7

deleteで作成されたポインタのみを呼び出す必要がありますoperator newnew通常によって割り当てられたメモリ位置で配置を使用する場合operator newは、安全に使用できますdelete(タイプとポインタが正しく取得されている場合)。ただし、任意のメモリに配置を使用できるnewため、通常はそのメモリを別の方法で管理し、オブジェクトのデストラクタを手動で呼び出します。

たとえば、この複雑で通常は不要なシナリオでは、delete配置を使用したメモリに対して安全ですが、それは以前にnew割り当てたためです。new

char* mem = new char[sizeof(MyObject)];
MyObject* o = new (mem) MyObject;

// use o

o->~MyObject(); // with placement new you have to call the destructor by yourself

delete[] mem;

ただし、これは違法です:

char mem[16]; // create a buffer on the stack, assume sizeof(MyObject) == 16

MyObject* o = new (mem) MyObject; // use stack memory to hold a MyObject
                                  // note that after placement new is done, o == mem
                                  // pretend for this example that the point brought up by Martin in the comments didn't matter

delete o; // you just deleted memory in the stack! This is very bad

別の見方をすれば、通常のによって以前に割り当てられたメモリの割り当てを解除するdelete だけnewです。配置を使用すると、通常によって割り当てられたメモリを使用するnew必要がないnewため、通常によって割り当てられていない可能性があるためnewdelete処理できません。

于 2011-08-14T17:30:11.370 に答える
5

いいえ、deleteはデストラクタを呼び出すだけでなく、メモリを解放するためですが、placement newを使用した場合は、malloc()またはスタックを使用して自分でメモリを割り当てている必要があります。ただし、デストラクタを自分で呼び出す必要があります。C++FAQも参照してください。

于 2011-08-14T17:30:43.997 に答える
5

編集1:プレースメントの削除がないことを知っています。しかし、なぜポインタを削除するだけでは、ポインタが指すメモリがどのように割り当てられているかを気にせずにメモリを削除できないのでしょうか。

メモリ割り当ての各フレーバーは、メモリの実装固有の追跡(通常はユーザーアドレスの前にあるヘッダーブロック)を使用するため、割り当て/割り当て解除は、正しくペアリングされた場合にのみ機能します。

  • newとペアリングする必要がありますdelete
  • new[]ペアにする必要があります(とdelete[]の混合は許しますが、ほとんどの実装)newnew[]
  • malloc揚げ物はペアにする必要がありますfree
  • CoTaskMemAllocとペアリングCoTaskMemFree
  • alloca何もないペア(スタックの巻き戻しが処理します)
  • MyCustomAllocatorとペアリングMyCustomFree

間違ったデアロケーターを呼び出そうとすると、予期しない動作が発生します(現在または後でセグメンテーション違反が発生する可能性があります)。deleteしたがって、他のものによって割り当てられたメモリを呼び出すとnew、悪い結果になります。

さらに、新しい配置は任意のアドレスで呼び出される可能性があり、割り当てられたアドレスでさえない可能性があります。大きなオブジェクトの中央にあるアドレスで呼び出すことも、メモリマップド領域で呼び出すことも、生の仮想コミット領域で呼び出すこともできます。deleteこれらすべての場合において、実装で指示されていることを実行しようとします。ヘッダーサイズを減算し、ヘッダーとして解釈newし、ヒープにリンクします。カブーム。

配置の新しいアドレスのメモリを解放する方法を知っているのはあなたです。なぜなら、そのメモリがどのように割り当てられたかを正確に知っているからです。deleteそれが知っていることだけをするでしょう、そしてそれは正しいことではないかもしれません。

于 2011-08-14T21:48:08.693 に答える
0

いいえ。配置-削除式はありません。

典型的なシナリオ:

void * const addr = ::operator new(sizeof(T));  // get some memory

try {
  T * const pT = new (addr) T(args...);    // construct
  /* ... */
  p->~T();                                      // nap time
}
catch (...) {
}
::operator delete(addr);  // deallocate
                          // this is _operator_-delete, not a delete _expression_

配置新規演算子には、正確に操作なしであることが義務付けられている対応する削除演算子void ::operator delete(void* [, size_t]) { }があることに注意してください。これは、のコンストラクタがT例外をスローした場合に呼び出されるものです。

于 2011-08-14T17:28:48.237 に答える
0

いいえ、新しい配置ではメモリが割り当てられないためです。以前に割り当てられたrawメモリで新しい配置を使用します。それが行う唯一のことは、オブジェクトのコンストラクターを呼び出すことです。

于 2011-08-14T17:31:02.780 に答える