【问题标题】:Why should I use placement new?为什么我应该使用新的展示位置?
【发布时间】:2012-02-07 21:23:54
【问题描述】:

看起来,placement new 在预分配的内存上创建了一个新对象,这是否意味着它会花费更少的时间?看起来它比使用旧的普通new 分配更快。那么,既然这样方便快捷,为什么不一直使用placement new呢?

【问题讨论】:

  • Placement new 不仅用于控制对象的位置,还可以用于大量低级调试(调试 CRT 使用它来跟踪分配并检测和跟踪泄漏)。
  • @ron - 如果您没有任何预分配的内存怎么办?

标签: c++ new-operator placement-new


【解决方案1】:

正常(nonplacement)new基本相当于做

T* ptr = static_cast<T*>(malloc(sizeof(T)));
new(ptr) T;

当然,由于错误检查等原因,现实看起来有点不同,但结果或多或少是相同的(通过不完全相同,您不能 delete 以这种方式分配的指针,而是您需要调用显式析构函数(ptr-&gt;~T()),然后使用free释放内存。

因此,placement new 确实应该比 nonplacement new 更快,因为它不需要分配内存。然而问题是内存需要分配到某个地方。因此,您实际上已经用对placement new 的调用和一些用于在某处分配的代码替换了对new 的调用(如果不是,为什么首先要使用new?)。很明显,这不太方便并且更容易出错。

现在您当然可以编写一种更快的分配方法,但为此您通常需要进行某种权衡。在不使用更多内存(用于更快识别空闲块的额外数据)或使其非常具体(编写单个对象大小的快速分配比一般对象大小更容易)的情况下,编写一个更快的分配器并不容易。最后,通常不值得付出努力(对于值得付出努力的场景,它可能已经完成,因此您可以使用现有的分配器(它可能在内部使用新的位置)。

当然有用于放置 new 的用途(有时您确实预先分配了内存),但这根本不是常见的情况

【讨论】:

  • 我的观点是,您几乎可以通过使用位置 new + malloc 完全重塑 new
  • @awoodland:我想我已经或多或少在我的回答中说过,所以没有任何评论的链接似乎有点多余,但无论如何。
  • 它的目的是同意我的投票,但也显示了如何处理分配失败和构造函数参数。
【解决方案2】:

对于大多数程序来说,这是完全没有必要的,因为它们的使用模式并没有必要。对于不使用堆的程序没有任何区别,而且很难正确处理(比你的操作系统更好,也就是说)。您也只能通过优化分配获得这么多。在大多数情况下,任何算法优化都会导致更大的整体加速。自定义分配器可以提供的许多保证(通过预分配内存保证分配的时间限制、低内存碎片)通常是不需要的。

肯定有一些程序可以从自己进行内存管理中受益,但它们很难识别。在你发现内存分配实际上是一个瓶颈之后,就更难找到更好的分配方案了。完成所有这些后,通常还是不值得麻烦。

【讨论】:

  • 投反对票的人会这么好心解释一下自己吗?我试图对 OP 的实际要求给出一个平衡的答案。也许我不熟悉不使用placement new 的另一个重要原因。
  • 大概是因为 1)这实际上并没有回答问题,2)发帖人没有说明他/她的用例,但如果他们问这个问题,为什么不教育他们呢? 3) 操作系统是针对一般情况构建的; Placement new 允许特定程序实现适合其特定用途的分配器。除非加上实际的答案,否则给出一个笼统的“可能没有必要”是没有帮助的。
  • @jzila 我的印象是,OP 在询问一般情况:为什么不经常使用放置新?我试图在编辑中更加强调不同的域。
【解决方案3】:

放置 new 的目的之一是使用自定义分配器来创建新对象并调用它们的构造函数。它并不总是更快,因为它与您的自定义分配器一样快。

【讨论】:

  • 在自定义分配器的情况下是必要的,并且您有一个需要调用构造函数的类。我在一个项目中遇到了一种情况,我们必须使用自定义分配器,它只返回适当大小的内存块,并且我需要分配的对象具有必须在构造函数中初始化的成员
【解决方案4】:

Placement new 用于将对象放置在内存中的特定位置可能需要更少的时间,因为您实际上避免了分配内存在此步骤

但是,它一定是在某个时间点分配的,在此之前可能需要一些时间。 如果您确实有理由将对象放置在预分配的内存中,那么使用它是有意义的。

这种new操作符的使用不是一次。更多详情here.

另外,请记住placement new 不会自动调用析构函数! 您必须手动为您的Foo foo; 执行foo-&gt;~Foo();

【讨论】:

    【解决方案5】:

    我发现,placement new 将使您的分配明显更快的唯一地方是,如果您有大量相同大小的对象,它们的生命周期有限,导致它们被频繁地分配和销毁。如果你不能保证这种行为,你最好使用默认的新实现。

    【讨论】:

      【解决方案6】:

      需要大量相同大小对象的应用程序通常可以从池(或批量)分配中看到显着的加速。基本上,您会为大量该对象分配一个大缓冲区(或页面),然后在请求对象时在其中调用placement new。虽然这可以大大加快速度,但对于大多数程序来说并不是必需的。

      尝试为实际上不需要它的程序执行此操作可能只会给您带来最小的加速,但可能会花费您大量的调试时间。

      所以真的看你需要什么;如果您要分配大量相同的对象,是的,放置 new 可能会更快。但只有几个对象?我不会打扰。

      不过,这并不总是时间问题。例如,您可以使用placement new 来保证堆上的对象对齐。您可以执行以下操作:

      void* buffer = aligned_malloc(sizeof(Object), 16); 
      Object* object = new (buffer) Waypoint();
      

      这对于某些类型是必需的,例如与 SSE 函数和寄存器一起使用的浮点数组。

      【讨论】:

        猜你喜欢
        • 2021-08-29
        • 2011-05-28
        • 1970-01-01
        • 2023-03-07
        • 2021-12-11
        • 1970-01-01
        • 2015-08-26
        • 2010-11-25
        • 1970-01-01
        相关资源
        最近更新 更多