问题 我为什么要使用新的展示位置?


看来, placement new 在预分配的内存上创建一个新对象,这是否意味着它需要更少的时间?看起来它比使用旧普通分配更快 new。然后,如果这样方便快捷,为什么不使用 placement new 每时每刻?


7153
2018-02-07 21:23


起源

这可能有所帮助: parashift.com/c++-faq-lite/dtors.html#faq-11.10 - Scott Hunter
Placement new不仅用于控制对象的位置,它还可以用于大量的低级调试(调试CRT使用它来跟踪分配并检测和跟踪泄漏)。 - ssube
@ron - 如果你没有任何预先分配的内存怎么办? - Bo Persson


答案:


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

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

当然,由于错误检查等现实看起来有点不同,但结果或多或少相同(通过不相同,你不能 delete 一个指针分配的方式,而你需要明确地调用析构函数(ptr->~T())然后使用释放内存 free)。

因此,放置new应该比非放置new更快,因为它不需要分配内存。但问题是需要在某处分配内存。所以你基本上已经取代了一个电话 new 打电话给 placement new 以及某些地方的分配代码(如果不是为什么你会使用 new 首先?)。很明显,这不太方便,更容易出错。

当然,你现在可以写一个更快的分配方法,但为此你通常需要做一些权衡。编写一个分配器并不容易,如果没有使用更多的内存(额外的数据可以更快地识别空闲块)或使其非常具体(编写单个对象的快速分配比一般的更容易)。最后,通常不值得付出努力(对于可能已经完成的努力值得花钱的情况,所以你可以使用现有的分配器(可能在内部使用placement new))。

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


4
2018-02-07 21:55



stackoverflow.com/questions/184537/... - Flexo♦
@awoodland:你的观点到底是什么? - Grizzly
我的观点是你几乎可以彻底改造 new 通过使用展示位置 new + malloc - Flexo♦
@awoodland:我认为我已经或多或少地在我的回答中说过,所以没有任何评论的链接似乎有点多余,但无论如何。 - Grizzly
它的目的是同意我的投票,但也展示了如何处理分配失败和构造函数参数。 - Flexo♦


对于大多数程序来说,这是不必要的,因为它们的使用模式不需要它。对于那些不使用堆的程序来说没有区别,并且很难做到正确(比你的操作系统更好)。您也可以通过优化分配获得如此多的收益。在大多数情况下,任何算法优化都将导致更大的总体加速。通常不需要定制分配器可以提供的许多保证(通过预分配的内存分配的保证时间限制,低内存碎片)。

肯定有程序可以从内存管理中受益,它们很难识别。在您发现内存分配实际上是瓶颈之后,找到更好的分配方案就更难了。当一切都完成后,仍然不值得麻烦。


3
2018-02-07 21:28



下选民会如此善良地解释自己吗?我试图对OP实际要求的内容给出一个平衡的答案。也许我不熟悉不使用的另一个重要原因 placement new。 - pmr
大概是因为1)这实际上没有回答问题,2)海报没有表明他/她的用例,但如果他们在询问它,为什么不教育他们呢? 3)操作系统是为一般情况而建的; placement new允许特定程序实现适合其特定用途的分配器。除非加上实际答案,否则给一般“可能没必要”是没有用的。 - jzila
@jzila我的印象是,OP正在询问一般情况:为什么常常不使用新的展示位置?我试图在编辑中更多地强调不同的域。 - pmr


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


2
2018-02-07 21:26



在自定义分配器的情况下,您需要一个需要调用构造函数的类。我遇到了一个项目的情况,我们必须使用自定义分配器,它只返回正确大小的内存块,而我需要分配的对象具有在构造函数中初始化HAD的成员 - Dan F


用于将对象放置在内存中特定位置的新位置可能需要较少的时间,因为您实际上避免分配内存 在这一步

但是,它必须在某个时刻分配,之前可能需要时间。 如果你真的有理由将对象放在预分配的内存中,那么使用它是有意义的。

这不是一次性使用  运营商。更多细节 这里

另外,请记住,placement new不会自动调用析构函数! 你必须做 foo->~Foo(); 为您 Foo foo; 手动。


2
2018-02-07 21:44





我发现放置new的唯一地方会使你的分配速度明显加快,如果你有大量相同大小的对象,它们的生命周期有限,导致它们经常被分配和销毁。如果您不能保证这种行为,那么最好使用默认的新实现。


1
2018-02-07 21:53





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

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

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

但是,这并不总是一个时间问题。例如,您可以使用placement new来保证对象在堆上的对齐。你可以这样做:

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

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


1
2018-02-07 22:24