Я пишу небольшую оболочку вокруг freeimage для загрузки изображений и захвата пикселей среди прочего. у меня есть PImage
класс, который имеет дело со всей загрузкой и отображением, и внутри него он содержит PixelColorBuffer
учебный класс. Я использую PixelColorBuffer
для удобного способа захватить unsigned char
с из texturebuffer
и преобразовать их в другой класс под названием color
(который я исключил, так как он работает нормально). Я также хочу иметь возможность устанавливать пиксели с помощью этого PixelColorBuffer
класс, поэтому он имеет colortobuffer
а также buffertocolor
, Я создаю экземпляр PixelColorBuffer
с указателем на где unsigned char array
is (примечание: содержит значения rgba для изображения). Тем не менее, это похоже на работу, но когда я звоню get(10, 10)
на изображении, которое загружается и отображается, я получаю следующее:
(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];
PImage
а также PixelColorBuffer
классы скомпилированы в .so
и связаны должным образом. Я предполагаю, что я делаю что-то не так с установкой указателя, это первый раз, когда я имел дело с указателями на указатели … все же я не могу на всю жизнь понять, что я делаю неправильно. Вот весь соответствующий код.
///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;
— вы инициализируете b как указатель на значение стека.
Измените аргумент на unsigned char*&
чтобы исправить эту непосредственную проблему с вашим кодом. Чтобы исправить долгосрочные проблемы, перестаньте возиться с указателями. (Это приведет к ошибке где-то еще, но это исправит неопределенное поведение здесь!)
(unsigned char *)
не используйте приведения в стиле C в коде C ++. Используйте приведения в стиле C ++, они оба менее опасны и говорят, что вы собираетесь делать.
unsigned char ** b
почему у вас есть указатель на указатель на буфер беззнаковых символов в любом случае? И почему ты слоняешься с буфером, не зная, как долго?
texturebuffer = new GLubyte[4*w*h];
в C ++ рекомендуется использовать некоторый класс владения для переноса распределений, чтобы вы знали, какой указатель «владеет» данными и отвечает за их очистку.
this->pixels = new PixelColorBuffer((unsigned char *) texturebuffer);
есть ли причина, по которой ваш PixelColorBuffer
нужно динамически распределять? Почему бы не иметь фактический PixelColorBuffer
в вашем классе / структуре, вместо накладных расходов и беспорядка размещения в бесплатном магазине?
Во-первых, научить PixelColorBuffer
как быть пустым. Во-вторых, не выделяйте его динамически. В-третьих, если вы пишете нетривиальный конструктор, который выделяет память, вы должны написать деструктор, конструктор копирования и operator=
, Вы можете отключить конструктор копирования и operator=
вместо того, чтобы писать их. (Google «правило трех C ++»)
Тогда всякий раз, когда вы обновляете texturebuffer
, скажи PixelColorBuffer
указать на новый источник пикселей. Это избавляет от необходимости иметь char**
в PixelColorBuffer
,
В идеале, хранить ваши texturebuffer
в управляемом буфере, как std::vector
Вместо того, чтобы использовать new
— зачем управлять памятью, когда это может делать кто-то другой? Это избавляет от необходимости писать деструктор (но вам все равно нужно отключить =
и копирование конструкции).
Это, вероятно, не вся история, а две очевидные проблемы:
PImage::PImage() {
this->pixels = new PixelColorBuffer((unsigned char *) texturebuffer);
}
Эта строка неверна, потому что texturebuffer
там неинициализирован. (Чтение из неинициализированных переменных приводит к неопределенному поведению).
PixelColorBuffer::PixelColorBuffer(unsigned char * b) {
this->b = &b;
}
Эта линия указывает this->b
в b
, которая является локальной переменной (параметром) в PixelColorBuffer::PixelColorBuffer
, После возврата конструктора this->b
неверный указатель