【发布时间】:2020-11-08 23:47:33
【问题描述】:
假设我们声明了一个 char* 缓冲区:
char *buf = new char[sizeof(int)*4]
//to delete:
delete [] buf;
或 void* 缓冲区:
void *buf = operator new(sizeof(int)*4);
//to delete:
operator delete(buf);
如果它们专门用于作为预分配内存的目的,它们会有什么不同?- 总是将它们转换为其他类型(而不是自行取消引用它们):
int *intarr = static_cast<int*>(buf);
intarr[1] = 1;
如果上面的代码不正确,也请回答,应该优先使用以下代码(仅考虑最终类型为 int 等基元的情况):
int *intarr = static_cast<int*>(buf);
for(size_t i = 0; i<4; i++){
new(&intarr[i]) int;
}
intarr[1] = 1;
最后,回答是否可以安全地删除类型为 void*/char* 的原始缓冲区,一旦使用后一种放置新的方法在其中创建其他类型。
值得澄清的是,这个问题是一个好奇的问题。我坚信,通过了解编程语言中什么是可能的和不可能的基础,我可以将它们用作构建块,并在将来需要时提出适合每个特定用例的解决方案。这不是一个 XY 问题,因为我没有想到具体的代码实现。
在任何情况下,我都可以在脑海中说出一些与这个问题相关的事情(特别是预分配的缓冲区):
有时您想为自定义分配创建内存缓冲区。有时甚至您希望将这些缓冲区与高速缓存行边界或其他内存边界对齐。几乎总是以更高性能的名义,有时是根据要求(例如 SIMD,如果我没记错的话)。请注意,对于对齐,您可以使用 std::aligned_alloc()
【问题讨论】:
-
在
void *存在之前,程序员使用char *。intarr[1] = 1;仍然可能是 UB,因为内存可能未与alignof(int)对齐。 -
当你用
operator new、static_cast分配原始内存到int*然后使用生成的指针访问数组元素,你得到UB。它可能会按预期工作,但在技术上它仍然是 UB。 -
@MatiasChara 如果要将其用作数组,则需要
[]版本的placement new。但要小心,因为它可能需要比n * sizeof(T)更多的内存。 -
@MatiasChara,如果你想在这个序列上使用指针算法(比如
arr[i]),不。同样,它可能会起作用,但按照标准是 UB,因此它可能会以不可预知的方式失败。 -
@Evg 如果你有一个水晶球并且可以预测实现将使用多少内存开销。不幸的是,数组放置 new 在实践中不是很有用。