我根据this gamedev.net post中的代码创建了一些自定义内存分配器。
本文中描述的一个实用程序模板声明如下:
template <class T> T* allocateNew(Allocator& allocator, T& t) {
return new (allocator.allocate(sizeof(T), alignof(T))) T(t);
}
*我将__alignof()
转换为对alignof()
的调用,因为我使用的是C ++ 11
我认为这段代码为新的T
对象分配内存,将t
堆栈对象从引用复制到新分配的堆内存,并将T*
指针返回给新对象。
通过这些假设,我将上面的代码转换为:
template <class T> T* allocateNew(Allocator& allocator, T& t) {
void *ptr = allocator.allocate (sizeof (T), alignof (T));
assert(ptr && "So that I don't dereference a null pointer");
* (T *) (ptr) = instance; // Casting void* to T* and then dereferencing
return (T *) ptr;
}
似乎工作得很好。我的问题是:
new
执行与void指针转换有什么不同吗?问候,TM3P
答案 0 :(得分:2)
第一个版本使用 placement new 在新分配的内存中复制构造对象。这是将原始byes转换为对象的正确,明确定义的方法。
您的版本将字节视为已经是对象(通过强制转换),然后为该对象分配一个新值,从而提供未定义的行为。如果T
是一个非常简单的类型,这可以是正常的,但不会比第一个版本快。如果类型有赋值运算符,则会出现非常严重的错误。
答案 1 :(得分:2)
new会做什么不同于void指针转换吗?
是;它构造一个新对象,而不是试图分配给一个实际上不存在的对象。
这两者之间是否有任何性能差异?
对于普通类型,初始化和赋值实际上是相同的,因此可能很少或没有区别。对于非平凡类型,它们调用不同的用户定义函数(构造函数与赋值运算符),这可能会做很多不同的事情。
第二个代码示例是否有任何漏洞?
对于非平凡类型,赋值运算符可能会在赋值之前对对象的状态进行假设,如果没有有效对象,可能会出现可怕的错误,将程序置于未定义的行为中。
tl; dr 放置新作品,狡猾的施法很糟糕。