如何在不使用 new 的情况下进行默认初始化

How to default-initialize without using new?

本文关键字:情况下 默认 初始化 new      更新时间:2023-10-16

我正在尝试实现我自己的std::vector容器,并且我正在使用realloc()来调整它的大小,以防止每次都删除和重新分配。使用以下代码:

buffer = new T[n]();

这将默认初始化数组的每个元素,并允许我立即开始访问它们。但是,由于标准规定内存must be previously allocated by malloc(), calloc() or realloc()使用realloc(),因此我无法使用new

我知道calloc()会将内存零初始化,但我不确定这是否会与new T[n]()具有相同的行为。使用 C 样式内存分配进行默认初始化的正确方法是什么?

首先,不,零初始化内存与为该内存应该包含的对象调用默认构造函数不同。你必须调用构造函数。因此,就正确性而言,malloccalloc并不重要;所以如果你要走那条路,用malloc - 它更快。

其次,realloc不会直接工作,因为它不知道如何复制对象。有些对象可以逐字节复制,对于这些类型,realloc是可以的。但对于大多数类型,复制涉及其他操作,您必须使用 copy 构造函数或 copy 赋值运算符来执行复制。因此,realloc可以在特殊情况下使用,但不能在一般情况下使用。

所以,你真的仅限于mallocfree,以及构造函数(通过放置new(和析构函数。

您可以使用以下语法调用具有任何类型的内存的任何构造函数:

::new (ptr) T(...arguments go here (if any)...);

您可能需要使用

#include <new>

它将为在 ptr 分配的内存调用 T 的构造函数。对于数组,您必须循环:

T* ptr=(T*)malloc(sizeof(T)*n);
for(int i=0;i<n;++i)
   ::new(ptr+i) T();

但是有了这个,不要调用删除!您必须为每个项目显式调用析构函数,然后使用正确的函数释放内存:

for(int i=0;i<n;++i)
   (ptr+i)->~T();
free(ptr);

在 realloc 的情况下,您必须确保 T 对象可以毫无问题地重新定位(字节到字节复制正常(。对于具有简单数据类型的结构,它应该是安全的。