问题:如何使用“展示新”来创建动态尺寸的数组?或者更具体地说,如何从预先分配的内存中为数组元素分配内存。
我使用以下代码:
void* void_array = malloc(sizeof(Int));
Int* final_array = new(void_array) Int;
这保证了final_array *(数组指针)是从void_array *保留的位置分配的。但是final_array元素呢?我希望它们也可以从预先分配的内存中分配。
P.S :我不得不说我正在使用一些API,它可以让我对磁贴体系结构进行一些控制。有一个功能与malloc完全相同,但也有其他功能,例如允许您控制已分配内存的属性。所以,我基本上需要做的是,使用类似malloc的函数来分配具有我想要的属性的内存(例如从哪个内存库,缓存在哪里等等)
答案 0 :(得分:6)
首先,让我们确保大家都同意内存分配和对象构建的分离。考虑到这一点,让我们假设我们有足够的内存用于对象数组:
void * mem = std::malloc(sizeof(Foo) * N);
现在,您无法使用placement array-new,because it is broken。正确的做法是分别构建每个元素:
for (std::size_t i = 0; i != N; ++i)
{
new (static_cast<Foo*>(mem) + i) Foo;
}
(只有指针算术才需要强制转换.place-new所需的实际指针只是一个空指针。)
这正是标准库容器的工作原理,以及标准库分配器的设计方式。关键是你已经知道元素的数量,因为你在初始内存分配中使用它。因此,您不需要C ++数组提供的魔力 - new
,这就是在某处存储数组大小并调用构造函数和析构函数。
销毁相反:
for (std::size_t i = 0; i != N; ++i)
{
(static_cast<Foo*>(mem) + i)->~Foo();
}
std::free(mem);
您必须知道的另一件事情是:异常安全。除非Foo
具有无投掷构造函数,否则上述代码实际上是不正确的。要正确编码,您还必须存储展开位置:
std::size_t cur = 0;
try
{
for (std::size_t i = 0; i != N; ++i, ++cur)
{
new (static_cast<Foo*>(mem) + i) Foo;
}
}
catch (...)
{
for (std::size_t i = 0; i != cur; ++i)
{
(static_cast<Foo*>(mem) + i)->~Foo();
}
throw;
}
答案 1 :(得分:1)
您应该覆盖malloc
并使用它,而不是使用自定义operator new()
。这不是运营商new
;有一个实际上称为operator new()
的函数,看似令人困惑,这是普通(非放置)运算符new
使用的函数,以获取构造对象的原始内存。当然,如果需要特殊的内存管理,只需要覆盖它;否则默认版本可以正常工作。
使用它的方法如下,假设您的数组大小为size
:
Int* final_array = static_cast<Int*>(size == 0 ? 0 : operator new(sizeof(Int) * size));
然后你可以独立构造和销毁每个元素。例如,对于元素n
:
// Create
new(final_array + n) Int; // use whatever constructor you want
// Destroy
(final_array + n)->~Int();