首页 > 解决方案 > 如何在 std::vectors 之间进行 std::copy当 T 有 const memers 时?

问题描述

我的主要目标是结合std::vectorompenMP进行一些并行计算。我想使用Z boson 的答案,每个线程都在自己的向量副本上工作,最后,我们std::copy从所有私有向量到全局向量。考虑这个例子:

#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. 我有充分的理由让那些consts 留在foo课堂上。是否有任何方法可以保留它们并且不会出现编译时错误?

  2. 是否可以使用移动语义来获得更好的性能(并可能解决问题 1)?

据我所知, 的元素std::vector必须存储为连续的内存块,所以我不确定移动语义是否适用于此。

标签: c++c++11containersopenmp

解决方案


您可以然后复制初始化它们,而不是调用resize然后复制分配您的元素:reserve

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));
}

如果目标是让每个线程将自己的数据并行复制到预先分配的内存中,这将不起作用。在这种情况下,您的选择是:

  • 从成员中删除const—— 一种相当务实的方法。

  • 使用未初始化的内存而不是向量:

      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);
      }
    

    使用这种方法,您需要正确调用析构函数 ( tree[i].~foo()) 和解除分配 ( ::operator delete(tree))。不过这会很棘手,因为您需要跟踪哪些线程复制初始化了它们的元素,哪些没有。


推荐阅读