使用C ++的“placement new”进行动态分配

时间:2012-11-06 14:50:57

标签: c++ malloc dynamic-arrays placement-new

问题:如何使用“展示新”来创建动态尺寸的数组?或者更具体地说,如何从预先分配的内存中为数组元素分配内存。

我使用以下代码:

void* void_array = malloc(sizeof(Int)); 
Int* final_array = new(void_array) Int;

这保证了final_array *(数组指针)是从void_array *保留的位置分配的。但是final_array元素呢?我希望它们也可以从预先分配的内存中分配。

P.S :我不得不说我正在使用一些API,它可以让我对磁贴体系结构进行一些控制。有一个功能与malloc完全相同,但也有其他功能,例如允许您控制已分配内存的属性。所以,我基本上需要做的是,使用类似malloc的函数来分配具有我想要的属性的内存(例如从哪个内存库,缓存在哪里等等)

2 个答案:

答案 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();