I am writing a small wrapper around freeimage for image loading and pixel grabbing among other things. I have a PImage class which deals with all loading and displaying, and inside this it holds a PixelColorBuffer class. I use the PixelColorBuffer for a convenient way to grab the unsigned chars from the texturebuffer and convert them into another class called color (which I excluded since it works fine). I also want to be able to set pixels using this PixelColorBuffer class, which is why it has colortobuffer and buffertocolor. I instantiate PixelColorBuffer with a pointer to where the unsigned char array is (note: that holds the rgba values for the picture). However, this seems to work, yet when I call get(10, 10) on an image that is loaded and displaying I get the following:
(GNU Debugger)
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bc66d9 in cprocessing::PixelColorBuffer::buffertocolor (this=<optimized out>, n=<error reading variable: Unhandled dwarf expression opcode 0x0>) at pixelcolorbuffer.cpp:17
17 c.rgba[0]=(*b)[(n*4)+0];
The PImage and PixelColorBuffer classes are compiled into a .so and linked properly. I am assuming I am doing something wrong with setting the pointer, this is the first time I’ve dealt with pointers to pointers… yet I can’t for the life of me figure out what I am doing wrong. Here is all relevant code.
///MAIN_PROGRAM.CPP
PImage t;
t.loadImage("image.png"); //loads image (works)
image(t, mouseX, mouseY); //draws image (works)
color c = t.get(10, 10); //SEGFAULT
///PIMAGE.HPP
class PImage {
public:
GLubyte * texturebuffer; //holds rgba bytes here
PixelColorBuffer * pixels;
PImage();
color get(int x, int y);
};
///PIMAGE.CPP
PImage::PImage() {
this->pixels = new PixelColorBuffer((unsigned char *) texturebuffer);
}
void PImage::loadImage(const char * src) {
//...snip...freeimage loading / opengl code ...
char * tempbuffer = (char*)FreeImage_GetBits(imagen);
texturebuffer = new GLubyte[4*w*h];
//FreeImage loads in BGR format, so we swap some bytes
for(int j= 0; j<w*h; j++){
texturebuffer[j*4+0]= tempbuffer[j*4+2];
texturebuffer[j*4+1]= tempbuffer[j*4+1];
texturebuffer[j*4+2]= tempbuffer[j*4+0];
texturebuffer[j*4+3]= tempbuffer[j*4+3];
}
//...snip...freeimage loading / opengl code ...
}
color PImage::get(int x, int y) {
return pixels->buffertocolor((y*w)+x);
}
///PIXELCOLORBUFFER.HPP
class PixelColorBuffer {
public:
unsigned char ** b;
PixelColorBuffer(unsigned char * b);
/**Converts a pixel from the buffer into the color
* @param n pixel ((y*width)+x)
* @return color*/
color buffertocolor(int n);
/**Converts a pixel from the buffer into the color
* @param n pixel ((y*width)+x)
* @param c color to put into buffer*/
void colortobuffer(int n, const color& c);
};
///PIXELCOLORBUFFER.CPP
PixelColorBuffer::PixelColorBuffer(unsigned char * b) {
this->b = &b;
}
color PixelColorBuffer::buffertocolor(int n) {
color c(0, styles[styles.size()-1].maxA);
c.rgba[0]=(*b)[(n*4)+0];
c.rgba[1]=(*b)[(n*4)+1];
c.rgba[2]=(*b)[(n*4)+2];
c.rgba[3]=(*b)[(n*4)+3];
return c;
}
void PixelColorBuffer::colortobuffer(int n, const color& c) {
(*b)[(n*4)+0] = c.rgba[0];
(*b)[(n*4)+1] = c.rgba[1];
(*b)[(n*4)+2] = c.rgba[2];
(*b)[(n*4)+3] = c.rgba[3];
}
this->b = &b;— you are initializing b to be a pointer to a stack value.Change the argument to a
unsigned char*&to fix this immediate problem with your code. To fix long term problems, stop messing around with pointers. (This will cause an error somewhere else, but it will fix the undefined behavior here!)(unsigned char *)don’t use C style casts in C++ code. Use the C++ style casts, they are both less dangerous and say what you intend to do.unsigned char ** bwhy do you have a pointer to a pointer to a buffer of unsigned characters anyhow? And why are you hanging around with a buffer without any idea of how long it is?texturebuffer = new GLubyte[4*w*h];in C++, it is a good idea to use some kind of ownership class to wrap allocations, so you know what pointer “owns” the data, and is responsible for cleaning it up.this->pixels = new PixelColorBuffer((unsigned char *) texturebuffer);is there any reason why yourPixelColorBufferneeds to be dynamically allocated? Why not have an actualPixelColorBufferin your class/struct, instead of the overhead and mess of putting it on the free store?First, teach a
PixelColorBufferhow to be empty. Second, don’t dynamically allocate it. Third, if you write a non-trivial constructor that allocates memory, you must write a destructor, a copy constructor andoperator=. You can choose to disable the copy constructor and theoperator=instead of writing them. (Google “rule of three C++”)Then whenever you update your
texturebuffer, tell thePixelColorBufferto point at a new source of pixels. This gets rid of the need to have achar**inPixelColorBuffer.Ideally, store your
texturebufferin a managed buffer, like astd::vectorinstead of usingnew— why manage memory when someone else can do it? This does away with a need to write a destructor (but you still need to disable=and copy construction).