分配但不构造大量 C++ 对象

allocate but don't construct a large array of C++ objects

在某些情况下,我的 C++14 程序需要 "block" 大约 1 亿 complex<float>,这需要接近 1 GB 的 RAM。我们可以安全地假设所需的内存可用。

但是分配一个新的 std::vector 真的很慢,因为复杂的构造函数被调用了 1 亿次。在我的机器上,代码需要大约一整秒来初始化数组。

相比之下,调用 calloc() 将分配的内存初始化为零,效果基本相同,将在非常短的毫秒数内 运行。

事实证明我们甚至不需要这个初始化,因为大型数组中的复合体将在不久后从外部源填充。因此,我正在考虑将 "block" 中对象的构造推迟到以后,然后直接从外部数据源构造它们。

所以我的问题是,是否有一种安全的惯用且高效的 C++ 方法来做到这一点,也许在整个过程中使用 C++ 移动语义?如果不是,我们决定简单地 malloc 内存块,那么我们可以简单地 reinterpret_cast 内存块到 complex<float> 的普通旧 C 数组吗?

感谢您的帮助

让-丹尼斯·穆伊斯

所以你的问题是你是否可以使用 malloc()。多年前,我对我的旧 C++ 编译器使用了相同的方法,并且它起作用了。但最后我不得不调用 free() 而不是 delete[]。我认为这是特定于实现的,因此您应该在编译器上尝试一下。

我强烈建议坚持使用 C++,避免自己手动管理内存。

标准库应该够用了。例如

std::vector< complex > my_vector;

// Reserve the necessary space without constructing anything
my_vector.reserve( 100'000'000); 

// construct the elements when needed
populate( my_vector ); 

如果您将 complex<float> class 的默认构造函数定义为空,这使得成员变量未初始化,那么考虑到编译器优化,这两个操作之间应该没有任何真正的区别已开启。

假设 complex class.

的定义如下
template <typename T>
struct complex
{
  complex() {}; // Empty constructor does nothing
  T a, b;
};

在 x86-64 gcc 6.2 和启用 -O2 的情况下使用 vector 初始化生成的程序集是:

std::vector<complex<float>> v(100);

    mov     edi, 800
    call    operator new(unsigned long)
    mov     rdi, rax
    call    operator delete(void*)

而手动调用mallocfree生成的程序集是:

auto v = malloc(100 * sizeof(complex<float>));
free(v);

    mov     edi, 800
    call    malloc
    mov     QWORD PTR [rsp+8], rax
    mov     rdi, QWORD PTR [rsp+8]
    call    free

如您所见,vector 实现不再为每个元素调用 complex<float> 的构造函数。 vector 的用法更加正确和可读,并且还利用了有助于防止内存泄漏的 RAII。