【问题标题】:Fast way of copying multidimensional array in C++在 C++ 中复制多维数组的快速方法
【发布时间】:2022-01-18 16:10:51
【问题描述】:

我有 C++ 结构的多维数组。

#define TOTALSTREAMS 5
#define SEQUENCEHISTORY 20
#define PROCESSINGSIZE 5
#define OVERLAPPINGSIZE 1
#define X_GRID   100//X_GRID and Y_GRID represents the whole building in CM
#define Y_GRID   70
typedef struct {
   uint64_t localid;
   uint64_t globalid;
   int  posture;  
   std::vector<float> feature;
} person;
typedef struct {   
   std::vector<person> people;
} griddata;

griddata History_host[SEQUENCEHISTORY][TOTALSTREAMS][Y_GRID][X_GRID];
griddata Processed_Array[PROCESSINGSIZE][TOTALSTREAMS][Y_GRID][X_GRID];

需要从一个数组复制到另一个数组。我所做的只是以简单的方式复制如下。它很慢。如何以更快的方式复制这样的数组?

          for(int i=0; i<PROCESSINGSIZE; i++){
             for(int j=0; j<TOTALSTREAMS; j++){
                for(int k=0; k<Y_GRID; k++){
                   for(int m=0; m<X_GRID; m++){
                      for(int n=0; n<History_host[i][j][k][m].people.size(); n++){
                         Processed_Array[i][j][k][m].people.push_back(History_host[i][j][k][m].people.back());
                      }
                   }
                }
             }
          }     

【问题讨论】:

  • 使用std::array,需要的行数更少。
  • 在C++中你不需要那个C结构声明,你可以直接struct griddata{...}
  • successive push_back BTW 可以省略。
  • 你的内部循环可能只是Processed_Array[i][j][k][m].people.assign(History_host[i][j][k][m].people.begin(), History_host[i][j][k][m].people.end());
  • @AlanBirtles 谢谢

标签: c++ arrays


【解决方案1】:

您发布的代码未正确复制数组内容。 任务

Processed_Array[i][j][k][m].people.push_back(History_host[i][j][k][m].people.back());

不会复制数组内容,只会多次添加源数组的最后一个元素。您应该使用索引 n 来访问相应的元素。

以下是一些提高复制速度的提示:

  • 使用 std::vector.reserve() 在使用 std::vector.push_back() 之前分配向量元素。向量将在没有初始大小的情况下动态增长,这是一项代价高昂的操作。
  • 尽量避免使用 std::vector 并使用固定大小的数组(如果可能)。使用 memcpy() 可以轻松复制固定大小的数组

【讨论】:

  • 我无法提前知道每个网格的人数。
  • 可以设置数组大小的上限吗?
【解决方案2】:

我认为最大的问题是这段代码太像C-like。

  • 对常量使用宏
  • 使用显式 C 数组
  • typedefC 中是一个很好的做法,在C++ 中已经过时了。

为了使它更像 C++ 代码:

constexpr size_t TOTALSTREAMS = 5;
constexpr size_t SEQUENCEHISTORY = 20;
constexpr size_t PROCESSINGSIZE = 5;
constexpr size_t OVERLAPPINGSIZE = 1;
constexpr size_t X_GRID = 100; //X_GRID and Y_GRID represents the whole building in CM
constexpr size_t Y_GRID = 70;

struct person{
   uint64_t localid;
   uint64_t globalid;
   int  posture;  
   std::vector<float> feature;
};

struct griddata{   
   std::vector<person> people;
};

using griddata_streams = std::array<std::array<std::array<griddata, X_GRID>, Y_GRID>, PROCESSINGSIZE>;

using history_host = std::array<griddata_streams, SEQUENCEHISTORY>;
using processed_array = std::array<griddata_streams, PROCESSINGSIZE>;

history_host History_host;
processed_array Processed_Array;

现在简单的赋值完成了这项工作,代码的其他部分保持不变。

现在谈谈性能。要改进,只有树选择:

  • 以上代码 - push_back 存在问题,它可以随着向量的增长多次重新分配向量缓冲区。使用std::vector::reserve 可以防止这种情况发生。
  • 使用 COW - Copy On Write 技术(无需额外的问题上下文即可完成)
  • 分析此代码应解决的问题并在那里寻找可能的优化。为此,我们只需要知道您的代码做什么以及您的输入数据的属性是什么。例如,有一种叫做稀疏矩阵的东西可以大大提高性能。

另请注意,您的原始代码有 UB: buffer overflow,因为 SEQUENCEHISTORY &gt; PROCESSINGSIZE

要复制它,您可以这样做:

std::copy_n(History_host.begin(), std::min(History_host.size(), Processed_Array.size()),
            Processed_Array.begin());

【讨论】:

  • 只分配每个griddata_streams 应该可以,不是吗?使用=
  • 类似for (int i = 0; i &lt; SEQUENCEHISTORY; i++) Processed_Array[i] = History_host[i];
  • @Afshin 是的,这就是 C++11 引入 std::array 的原因之一。
  • 这个for 循环是错误的。 UB - 缓冲区溢出,因为SEQUENCEHISTORY &gt; PROCESSINGSIZE - 我已经更新了答案。
  • hm...在他的代码中,他循环处理 PROCESSINGSIZE。我犯了一个错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-04
  • 2016-02-13
  • 1970-01-01
  • 2014-04-27
  • 2014-03-18
相关资源
最近更新 更多