简体   繁体   中英

Fast way of copying multidimensional array in C++

I have multidimensional array of Struct in 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];

Need to copy from one array to another. What I did was just copy in simple way as follows. It is slow. How can I copy such array in faster way?

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

The code you have posted does not copy the arrays content properly. The assignment

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

will not copy the arrays content, but only add the last element of the source array several times. You should use the index n to access the appropriate element.

Here are some hints to increase the copy speed:

  • use std::vector<>.reserve() to allocate the vectors elemets before using std::vector<>.push_back(). Vectors will grow dynamicaly of no initial Size is given, this is a costly operation.
  • Try to avoid the usage of std::vector<> and use fixed size arrays (if possible). Fixed size arrays can easily copied with memcpy()

You could use std::copy :

//inner loop
for (size_t n = 0; n < History_host[i][j][k][m].people.size(); n++) {
    std::copy(History_host[i][j][k][m].people.begin(), 
        History_host[i][j][k][m].people.end(), 
        Processed_Array[i][j][k][m].people.begin());
}
//...

It seems to be a better option when compared to direct assignment or Alan's sugestion. You can see here all the 3 methods side by side.

Still, you don't explain exactly what this is for, it's possible there are better options to do what you need. You could be facing the XY problem .

Biggest problem I see it that this code is to much C -like.

  • use of macros for constant
  • use of explicit C-array
  • typedef which is a good practice in C and obsolete in C++ .

To make this more like C++ code:

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;

Now simple assignment does the job and other parts of code remains unchanged.

Now about performance. To improve there are only tree choices:

  • above code - there is problem with push_back it can reallocate vector buffer multiple times as vector grows. Use of std::vector::reserve can prevent this.
  • use COW - Copy On Write technique (it can be done without extra context of your problem)
  • analyze problem which this code should solve and look there for possible optimizations. For this we just have to know what your code does and what are properties of your input data. For example there is something called sparse matrix which could greatly improve performance.

Note also that your original code has UB: buffer overflow, since SEQUENCEHISTORY > PROCESSINGSIZE .

To copy this you can do this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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