【问题标题】:Can char* and void* be used interchangeably in all cases as buffers? c++char* 和 void* 在所有情况下都可以互换用作缓冲区吗? C++
【发布时间】: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 newstatic_cast 分配原始内存到int* 然后使用生成的指针访问数组元素,你得到UB。它可能会按预期工作,但在技术上它仍然是 UB。
  • @MatiasChara 如果要将其用作数组,则需要 [] 版本的placement new。但要小心,因为它可能需要比 n * sizeof(T) 更多的内存。
  • @MatiasChara,如果你想在这个序列上使用指针算法(比如arr[i]),不。同样,它可能会起作用,但按照标准是 UB,因此它可能会以不可预知的方式失败。
  • @Evg 如果你有一个水晶球并且可以预测实现将使用多少内存开销。不幸的是,数组放置 new 在实践中不是很有用。

标签: c++ memory


【解决方案1】:

由于technicalitydelete [] buf;可能会在buf失效后被认为是UB,因为字符数组由于内存的重用而被破坏。

我不希望它在实践中引起问题,但是使用 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);

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

【讨论】:

    猜你喜欢
    • 2022-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多