My main goal is to combine std::vector
with ompenMP
to make some parallel computations. I want to go with Z boson's answer where each thread works on its own copy of vector and at the end, we std::copy
from all private vectors to the global one. Consider this example:
#include<iostream>
#include <vector>
const int N = 10;
class foo {
public:
foo(int i) : heavy(i), ptr(nullptr) { }
foo() : heavy(0), ptr(nullptr) { } // needed by std::vector.resize()
const int heavy; // type is not assignable ...
foo * const ptr; // drop const to make it work
};
int main() {
std::vector<foo> tree;
tree.resize(N);
for (int i = 0; i < N; i = 2) {
std::vector<foo> vec_private;
vec_private.emplace_back(i );
vec_private.emplace_back(i 1);
std::copy(vec_private.begin(), vec_private.end(), tree.begin() i);
}
for (auto& x : tree)
std::cout << x.heavy << '\n';
return 0;
}
I have a good reason to keep those
const
s infoo
class. Is there any walk-around to keep them and not get a compile-time error?Would it be possible to employ move semantics for better performance (and possibly to solve problem 1) ?
For all I know the elements of std::vector
must be stored as a contiguous block of memory, so I'm not sure if move semantics applies here.
CodePudding user response:
Instead of calling resize
and then copy-assigning your elements, you can reserve
and then copy-initialize them:
std::vector<foo> tree;
tree.reserve(N);
for (int i = 0; i < N; i = 2) {
...
std::copy(vec_private.begin(), vec_private.end(), std::back_inserter(tree));
}
This won't work if the goal is to have each thread copy their own data into a pre-allocated memory, in parallel. In such a case your options are:
Remove the
const
from the member -- a rather pragmatic approach.Use uninitialized memory instead of a vector:
foo *tree = (foo*)::operator new(sizeof(foo)*N); for (int i = 0; i < N; i = 2) { ... // then each thread can do: std::uninitialized_copy(vec_private.begin(), vec_private.end(), tree i); }
With this approach you'll need to call the destructors (
tree[i].~foo()
) and deallocate (::operator delete(tree)
) correctly. This will be tricky though, because you'll need to keep track which threads copy-initialized their elements and which didn't.