简体   繁体   English

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

[英]C++: Allocate memory for an std::vector then initialize its elements in parallel

I have a use case for creating an std::vector with many elements, each of which is of a simple, but non-primitive, type (POD struct).我有一个用例,用于创建一个包含许多元素的std::vector ,每个元素都是一个简单但非原始的类型(POD 结构)。 The vector and type are sufficiently large/complex that in the following,向量和类型足够大/复杂,在下面,

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

the resize call is noticeably slow. resize调用明显缓慢。 And it's wasteful because resize is default-initializing all those entries, then I'm going through in a loop and setting them all to their correct/useful values.这很浪费,因为resize是默认初始化所有这些条目,然后我在循环中进行并将它们全部设置为正确/有用的值。

What I would like to do is to allocate all the memory for the vector, but not initialize any of the entries, then go through in parallel and initialize all the entries, eg with OpenMP我想做的是为向量分配所有内存,但不初始化任何条目,然后并行执行并初始化所有条目,例如使用 OpenMP

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

However, reserve doesn't actually change the size of v , so I'd have to keep doing push_back in my loop, which won't maintain the proper ordering of the elements (which matters in my use case);但是, reserve实际上并没有改变v的大小,所以我必须在我的循环中继续执行push_back ,这不会保持元素的正确顺序(这在我的用例中很重要); I really want to write something like v[i] = ... in my loop body.我真的很想在我的循环体中写一些类似v[i] = ...东西。

Is there a way to allocate/"initialize" a vector without initializing any of its elements, and to then fill in / initialize all the elements in parallel?有没有办法在不初始化任何元素的情况下分配/“初始化”一个向量,然后并行填充/初始化所有元素?

Your options are:您的选择是:

After you've performed the resize, you can use OpenMP in the usual ways.执行调整大小后,您可以按常规方式使用 OpenMP。

It depends on the default constructor for your type U. If the default constructor is cheap, it is very unlikely that you will gain anything parallelizing it.这取决于你的类型 U 的默认构造函数。如果默认构造函数很便宜,你就不太可能获得并行化它的任何东西。

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

If your default constructor is expensive, it would make more sense to split it in two parts: One for default initialization and a function for the actual initialization.如果你的默认构造函数很昂贵,那么将它分成两部分会更有意义:一个用于默认初始化,一个用于实际初始化的函数。

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

In both alternatives, the regular resize or assign call to the vector would be very hard to beat.在这两种选择中,对向量的常规调整大小或分配调用都很难被击败。

If you really are set in doing things this way, you could use a reinterpret_cast to an array.如果您确实打算以这种方式做事,则可以对数组使用 reinterpret_cast。 This way, the default constructor won't be called.这样,就不会调用默认构造函数。

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

I strongly advise against this last option.我强烈建议不要使用最后一个选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM