首页 > 解决方案 > char* 和 void* 在所有情况下都可以互换用作缓冲区吗?C++

问题描述

假设我们声明了一个 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()

标签: c++memory

解决方案


由于技术上的原因,由于内存的重用导致字符数组被破坏而失效后,delete [] buf;可能会被认为是UB 。buf

我不希望它在实践中引起问题,但是使用 operator new 的原始内存不会受到这种技术性的影响,也没有理由不喜欢它。

更好的是使用这个:

T* memory = std::allocator<T>::allocate(n);

因为这也适用于过度对齐的类型(与您的建议不同),并且很容易用自定义分配器替换。或者,只需使用 std::vector


for(size_t i = 0; i<4; i++){
    new(&intarr[i]) int;
}

有一个标准功能:

std::uninitialized_fill_n(intarr, 4, 0);

好的,它使用实际值进行初始化略有不同,但这可能是更好的做法。


推荐阅读