C ++:为std :: vector分配内存,然后并行初始化其元素

时间:2019-12-17 19:25:03

标签: c++ vector openmp

我有一个用许多元素创建std::vector的用例,每个元素都是简单但非基本的类型(POD结构)。向量和类型足够大/复杂,如下所示:

std::vector<U> v;
v.resize(1000000000);
for(size_t i=0;i<v.size();++i){/* initialize v[i] */}

resize的调用速度很慢。而且这很浪费,因为resize是默认初始化所有这些条目的,然后循环进行,并将它们全部设置为正确/有用的值。

我想做的是为向量分配所有内存,但不初始化任何条目,然后并行进行并初始化所有条目,例如使用OpenMP

std::vector<U> v;
v.reserve(1000000000);
#pragma omp parallel for
for(size_t i=0;i<v.size();++i){/* initialize v[i] */}

但是,reserve实际上并没有改变v的大小,因此我不得不在循环中继续执行push_back,这将不会保持元素(在我的用例中很重要);我真的很想在循环体内编写类似v[i] = ...的内容。

有没有一种方法可以在不初始化任何元素的情况下分配/“初始化”向量,然后并行填充/初始化所有元素?

2 个答案:

答案 0 :(得分:4)

您的选择是:

  • 用其他替换项(例如uvector)替换std::vector
  • 使用某种库来调整大小而无需初始化,例如来自Facebook的UninitializedMemoryHacks

执行调整大小后,可以按常规方式使用OpenMP。

答案 1 :(得分:3)

这取决于类型U的默认构造函数。 如果默认构造函数便宜,那么几乎不可能获得并行化的任何东西。

struct U {
   int a, b, c;
   U():a(0), b(1), c(2) {}
};

如果您的默认构造函数很昂贵,则将其分为两部分会更有意义:一个用于默认初始化,一个用于实际初始化的函数。

struct U {
   vector<int> a;
   U() {}
   void init(int n) { a.resize(n); }
};

在这两种选择中,很难对向量进行常规的调整大小或分配调用。

如果您确实对使用这种方法有所了解,则可以对数组使用reinterpret_cast。这样,默认的构造函数将不会被调用。

U * u_array = reinterpret_cast<U*>(malloc(100*sizeof(U)));

我强烈建议不要使用最后一个选项。