Home > Net >  How to std::copy between std::vectors<T> when T has const memers?
How to std::copy between std::vectors<T> when T has const memers?

Time:11-08

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;
}
  1. I have a good reason to keep those consts in foo class. Is there any walk-around to keep them and not get a compile-time error?

  2. 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.

  • Related