C++ 为什么我要使用新的布局?

C++ 为什么我要使用新的布局?,c++,new-operator,placement-new,C++,New Operator,Placement New,看起来,placement new在预先分配的内存上创建了一个新对象,那么这是否意味着它将花费更少的时间?看起来它比使用旧的普通新的更快。那么,如果这样做既方便又快捷,为什么不一直使用placement new?placement new的目的之一是使用自定义分配器创建新对象,并调用它们的构造函数。它并不总是更快,因为它只与您的自定义分配器一样快。对于大多数程序来说,这是不必要的,因为它们的使用模式不需要这样做。对于那些不经常使用堆的程序来说,这没有什么区别,而且很难做到正确(也就是说,比您的操

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

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

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


确实有一些程序可以从内存管理中获益,它们只是很难识别。在您发现内存分配实际上是一个瓶颈之后,更难找到更好的分配方案。当所有这些都完成后,通常仍然不值得这么麻烦。

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

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

这并不是这种新操作符的单一用途。更多细节

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

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

正常(非置换)
new
基本上等同于

T* ptr = static_cast<T*>(malloc(sizeof(T)));
new(ptr) T;
T*ptr=static_cast(malloc(sizeof(T));
新(ptr)T;
当然,由于错误检查等原因,实际情况看起来有点不同,但结果或多或少是相同的(通过不相同,您不能
删除以这种方式分配的指针,相反,您需要显式地调用析构函数(
ptr->~t()
),然后使用
空闲
)释放内存)

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

当然,现在您可以编写一个更快的分配方法,但为此,您通常需要进行某种折衷。如果不使用更多内存(用于更快地识别空闲块的额外数据)或使其非常具体(编写单个objectsize的快速分配比一般分配容易得多),那么编写速度更快的分配器是不容易的。最后,它通常不值得付出努力(对于scenarious来说,在值得付出努力的地方,它可能已经完成了,因此您可以使用现有的分配器(可能在内部使用新的位置))


当然,新的布局也有一些用途(有时您确实预先分配了内存),但这并不是常见的情况

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

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

所以,真正看看你需要什么;如果要分配大量相同的对象,是的,放置新对象可能会更快。但就几个东西?我不想麻烦了

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

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

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

这可能会有所帮助:Placement new不仅用于控制对象的位置,还可用于大量的低级调试(调试CRT使用它跟踪分配、检测和跟踪泄漏).@ron-如果没有任何预分配的内存怎么办?这在自定义分配器的情况下是必要的,并且您有一个需要调用构造函数的类。在一个项目中,我遇到了一种情况,我们必须使用自定义分配器,它只返回大小合适的内存块,我需要分配的对象有必须在构造函数中初始化的成员。下面的投票者能解释一下吗?我试图对OP的实际问题给出一个平衡的答案。也许我不熟悉另一个不使用
placement new
的重要原因。大概是因为1)这并没有真正回答问题,2)海报没有指出他/她的用例,但如果是这样的话