简体   繁体   中英

Unable to access elements of vector<vector<?>>

I have this class where the only atribute is a vector<vector<?>> like this:

struct Pixel {
    float r, g, b;
};

class Test {
private:
  vector<vector<struct Pixel>> pixels;
public:
  void read(std::string filename);
}

The method read is where first I read data from a file and put in a 1d array:

std::vector<pixel> v;

while(getline(file, line_pixels)) {
  if(line_pixels.size() > 0 && line_pixels.at(0) != '#') {
    std::stringstream ss(line_pixels);
    std::string value;
    while(getline(ss, value, ' ')) {
      pixel p;
      p.r = p.g = p.b = stoi(value);
      v.emplace_back(p);
    }
  }
}

after that I transfer the data from this 1d vector to the 2d vector pixels . I have tried to do this in this 2 ways:

int index = 0;
size_t h = stoi(height), w = stoi(width);
for(size_t i=0; i<h; i++) {
  std::vector<pixel> row;
  for(size_t j=0; j<w; j++)
    row.push_back(v[index++]);
  pixels.push_back(row);
}

with this code, when I try access any element from pixels with something like pixel[index] , I got a segmentation fault error.

The other option I have tried is that:

size_t h = stoi(height), w = stoi(width);
pixels.resize(h);
for(size_t i=0; i<h; i++)
  pixels[i].resize(w);
for(size_t i=0; i<v.size(); i++) {
  int row = i / w;
  int col = i % w;
  pixels[row][col] = v[i];
}

with this code, I got an segmentation fault error in that resize line.

Anyone can tell me the correct way to do that?

UPDATE

full code is divided in this 2 projects: https://github.com/klebermo/codec contains the classes Netpbm and Bitmap where the read method is implemented. https://github.com/klebermo/game uses the methods from the previous link.

Like other people said the error is not in the code snippets you posted. This is why people want a minimal reproducable self-contained code example, to narrow down the error.

The actual error (or one of the actual errors) is in this line:

float * vertices = image.toArray().data();

Written out in a more expanded form this expression means:

float * vertices;
{
    std::vector<float> temp = image.toArray();
    vertices = temp.data();
} // temp gets destroyed here, since it goes out of scope.
// accessing vertices after this point is undefined behavior
// because the memory it points to was deleted by the 
// destructor of temp

This means that the access to vertices after that one line cause undefined behavior, especially writing to it will corrupt other objects often times.

You can keep the vector around for the same duration as vertices to avoid this. Also, don't call delete on a pointer that was managed by a std::vector.

std::vector<float> vertices_vec = image.toArray();
float *vertices = vertices_vec.data();

This way vertices will keep pointing to valid data as long as vertices_vec does not go out of scope.

edit:

Additionally I guess the image read-in code doesn't have bounds checking in all cases, so if the input-file is invalid you might get additional issues there. So you could add some more assertions/debug checks with bounds-checking in there.

Edit2:

You are violating the one definition rule.

In one header ( Netpbm/src/netpbm.hpp ) you have

class Netpbm {
protected:
  std::vector<std::vector<pixel>> pixels;
public:
  virtual void read_file(std::string file_name) = 0;
  virtual void write_ascii_file(std::string file_name) = 0;
  virtual void write_binary_file(std::string file_name) = 0;

  int getHeight();
  int getWidth();
  std::vector<float> toArray();
};

and in another header ( Netpbm/include/netpbm.hpp ) you have

class Netpbm {
public:
  virtual void read_file(std::string file_name) = 0;
  virtual void write_ascii_file(std::string file_name) = 0;
  virtual void write_binary_file(std::string file_name) = 0;

  int getHeight();
  int getWidth();
  std::vector<float> toArray();
};

These two have different sizes, you are compiling parts of the code assuming one size and other parts of the code assuming the other size. Therefore corrupting the stack. If the consuming code doesn't know the vector is supposed to be there, then the generated constructor will never initialize it, so you are accessing a vector that you never called the constructor on.

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