我可以对用新放置分配的指针调用delete吗?

发布于 2024-11-29 15:53:03 字数 295 浏览 4 评论 0原文

我们可以对分配有placement new的指针调用delete吗?如果没有那为什么?请详细解释一下。

我知道没有放置删除。但我想知道为什么只是删除操作者不能删除内存而不关心指针指向的内存是如何分配的?

delete 正在做两件事:

  1. 调用 detrucor
  2. 释放内存

我认为删除没有理由无法在通过放置 new 创建的对象上调用这两个操作中的任何一个。知道原因吗?

Can we call delete on the pointer which is allocated with the placement new? If no then why? Please explain in details.

I know that there is no placement delete. But I wonder why just delete opetator can not delete the memory without caring how that memory on which the pointer points is allocated?

delete is doing two things:

  1. Calls destrucor
  2. Frees memory

And I see no reaason for delete not to be able to call either of these two operations on the object which was created by placement new. Any idea about reasons?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

踏月而来 2024-12-06 15:53:03

您只能对使用operator new 创建的指针调用delete。如果您将放置new与由普通operator new分配的内存位置一起使用,那么您可以安全地对其使用delete(前提是您得到类型和指针正确)。但是,您可以在任何内存上使用放置new,因此您通常会以其他方式管理该内存并手动调用对象的析构函数。

例如,在这种复杂且通常不必要的情况下,可以安全地删除您使用放置new的内存,但这只是因为您使用new<分配了它/code> 之前:

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分配的内存,因此有可能没有被分配普通newdelete无法处理。

You must only call delete on pointers that were created with operator new. If you use placement new with a memory location that was allocated by the normal operator new then you may safely use delete on it (provided you get the types and pointers right). However, you can use placement new on any memory, so you usually will manage that memory some other way and call the object's destructor manually.

For instance, in this convoluted and usually unnecessary scenario, it is safe to delete the memory you used placement new on, but only because you allocated it with new before:

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;

However, this is illegal:

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

Another way to think of it is that delete only deallocates memory allocated previously by the normal new. With placement new, you do not have to use memory that was allocated by the normal new, so with the possibility of not having been allocated by normal new, delete cannot deal with it.

国产ˉ祖宗 2024-12-06 15:53:03

EDIT1:我知道没有展示位置删除。但我想知道为什么只是
删除操作者无法删除内存而不关心如何
指针所指向的内存分配在什么位置?

因为每种类型的内存分配都使用一些特定于实现的内存跟踪(通常是用户地址之前的标头块),这使得分配/释放只有在正确配对时才能工作:

  • new 必须配对与 delete
  • new[] 必须与 delete[] 配对(尽管大多数实现可以混合使用 new>新[]
  • malloc 和 Frieds 必须与 free 配对
  • CoTaskMemAllocCoTaskMemFree 配对
  • alloca 不配对(堆栈展开会处理它)
  • MyCustomAllocatorMyCustomFree 配对

尝试调用错误的释放器将导致不可预测的行为(现在很可能是段错误或 之后)。因此,对除 new 之外的任何其他内存分配的内存调用 delete 都会导致不好的结果。

此外,新的放置可以在任何地址上调用,甚至可能不是分配的地址。它可以在位于某个较大对象中间的地址上调用,可以在内存映射区域上调用,也可以在原始虚拟提交区域上调用,一切都可以。在所有这些情况下,delete 都会尝试执行其实现告诉他要做的事情:减去标头大小,将其解释为新标头,将其链接回堆。轰隆隆。

知道如何释放新地址内存的人是,因为你确切地知道该内存是如何分配的。 delete 只会做它知道的事情,而且可能不是正确的事情。

EDIT1: I know that there is no placement delete. But I wonder why just
delete opetator can not delete the memory without caring how that
memory on which the pointer points is allocated?

Because each flavour of memory allocation uses some implementation specific tracking of the memory (usually a header block that precedes the user address) and this make the allocation/deallocation to work only when paired up correctly:

  • new must pair with delete
  • new[] must pair with delete[] (most implementations though forgive mixing the newand new[])
  • malloc and frieds must pair with free
  • CoTaskMemAlloc pairs with CoTaskMemFree
  • alloca pairs with nothing (stack unwinding takes care of it)
  • MyCustomAllocator pairs with MyCustomFree

Attempting to call the wrong deallocator will result in unpredictable behavior( most likely seg fault now or later). Therefore calling delete on memory allocated by anything else other than new will result in bad things.

Furthermore the placement new may be called on any address, may not even be an allocated address. It can be called on an address located in the middle of some larger object, it may be called on a memory mapped region, it may be called on a raw virtual committed region, anything goes. delete woul attempt, in all these cases, to do what its implementation tell him to do: subtract the header size, interpret it as a new header, link it back into the heap. Kaboom.

The one that know how to release the memory of a placement new address is you, since you know exactly how was that memory allocated. delete will only do what it knows, and it may not be the right thing.

情愿 2024-12-06 15:53:03

不,因为delete不仅调用析构函数,而且还释放内存,但如果您使用placement new,则必须自己使用malloc()或堆栈分配内存。但是,您必须自己调用析构函数。另请参阅 C++ 常见问题解答

No, since delete not only calls the destructor but also frees the memory, but if you used placement new you must have allocated the memory yourself using malloc() or stack. You do, however, have to call the destructor yourself. Also see the C++ FAQ.

人间不值得 2024-12-06 15:53:03

否。没有放置删除表达式。

典型场景:

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 的构造函数抛出异常,就会调用这个函数。

No. There is no placement-delete expression.

Typical scenario:

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_

Note that the placement-new operator does have a corresponding delete operator which is mandated to be precisely void ::operator delete(void* [, size_t]) { }, a no-op; this is what gets called if the constructor of T throws an exception.

不喜欢何必死缠烂打 2024-12-06 15:53:03

不,因为新的放置不会分配任何内存。您可以在先前分配的原始内存上使用新的放置。它唯一做的就是调用对象的构造函数。

No, because a placement new doesn't allocate any memory. You use placement new on previously allocated raw memory. The only thing it does is call the constructor of the object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文