2

I`m writing a code for which I'm using a 3 dimensional boost multiarray to save coordinates. But I always get a segmentation fault at some point. How are boost multiarray sizes limited and how can I get around those limits?

Here is a simplified test code that reproduces the problem:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <string>
#include <algorithm>
#include <map>

#include <boost/multi_array.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include "Line.h"

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>

typedef struct {
    Eigen::Vector3d coords;
    int gpHostZone;
    int gpHostFace;
    int calculated;
} Vertex;


class LGR {
public:
    LGR (int i, int j, int k) :
        grid(boost::extents[i][j][k])
    {
    };

    std::string name;
    std::vector<int> hostZones;
    std::vector<int> refine;
    boost::multi_array<Vertex*, 3> grid;
    std::vector<double> data;
 };

 int main(void){
   LGR lgr(11,11,21);
   std::cout << lgr.grid.size();
   std::vector<LGR> v;
   std::vector<Vertex> vertexDB;
   for(int i = 0; i < 1; i++ ){

     for(int j = 0; j < lgr.grid.size(); j++ ){
       for(int k = 0; k < lgr.grid[0].size(); k++ ){
         for(int l = 0; l < lgr.grid[0][0].size(); l++ ){
           Vertex coord;
           coord.coords << i,j,k;
           coord.gpHostZone = 0;
           coord.gpHostFace = 0;
           coord.calculated = 0;
           vertexDB.push_back(coord);
           lgr.grid[j][k][l] = &(vertexDB.back());
         }
       }
     }

     for(int j = 0; j < lgr.grid.size(); j++ ){
       for(int k = 0; k < lgr.grid[0].size(); k++ ){
         for(int l = 0; l < lgr.grid[0][0].size(); l++ ){
           std::cout << "At ("<< i << ","<< j << ","<< k << "," << l << ")\n";
           std::cout << lgr.grid[j][k][l]->coords<<"\n\n";
         }
       }
     }
   }
   return 1;
 }

Please do not comment on the includes. I just copy and pasted from the actual code. Most of the are probably not needed here. The dimensions are from a real example, so I actually need those kind of dimensions (and probably more).

alfC
  • 14,261
  • 4
  • 67
  • 118
Myrkjartan
  • 166
  • 3
  • 16
  • `lgr.grid[j][k][l] = &(vertexDB.back());` -- It is not a good idea to store pointers to items in a vector. If the vector becomes resized iterators and pointers to items become invalidated. – PaulMcKenzie Oct 05 '16 at 13:16

1 Answers1

2

The following is a definite issue that leads to undefined behavior, and doesn't have anything to do with boost::multiarray.

These lines:

std::vector<Vertex> vertexDB;
//...
vertexDB.push_back(coord);
lgr.grid[j][k][l] = &(vertexDB.back());

resizes the vertexDB vector and then stores a pointer to the last item in the vector to lgr.grid[j][k][l]. The problem with this is that pointers and iterators to items in a vector may become invalidated due to the vector having to reallocate memory when resizing the vector.

This manifests itself later here, in the subsequent loop:

std::cout << lgr.grid[j][k][l]->coords<<"\n\n";

There is no guarantee that the address you assigned previously is valid.

A quick fix for this is to use a std::list<Vertex>, since adding items to a std::list does not invalidate iterators / pointers.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • OK, now i feel kinda stupid. After you explained it, it's an obvious problem. And using a List has worked fine for the test code(unfortunatly i can't test the real code, because somehow a class i need got totally destroyed and now i have to recreate it.....). Well whatever, it works. Thank you PaulMcKenzie... – Myrkjartan Oct 06 '16 at 06:45