c++ c++11 opengl

El objeto OpenGL en la clase C++ RAII ya no funciona



c++11 (1)

Tengo un objeto OpenGL en una clase de C ++. Como estoy empleando RAII, quiero que el destructor lo elimine. Entonces mi clase se parece a:

class BufferObject { private: GLuint buff_; public: BufferObject() { glGenBuffers(1, &buff_); } ~BufferObject() { glDeleteBuffers(1, &buff_); } //Other members. };

Esto parece que funciona. Pero cada vez que hago algo de lo siguiente, empiezo a recibir varios errores de OpenGL cuando lo uso:

vector<BufferObject> bufVec; { BufferObject some_buffer; //Initialize some_buffer; bufVec.push_back(some_buffer); } bufVec.back(); //buffer doesn''t work. BufferObject InitBuffer() { BufferObject buff; //Do stuff with `buff` return buff; } auto buff = InitBuffer(); //Returned buffer doesn''t work.

¿Que esta pasando?

Nota: este es un intento de construir una respuesta canónica a estas preguntas.


Todas esas operaciones copian el objeto C ++. Como su clase no definió un constructor de copia, obtiene el constructor de copia generado por el compilador. Esto simplemente copia a todos los miembros del objeto.

Considere el primer ejemplo:

vector<BufferObject> bufVec; { BufferObject some_buffer; //Initialize some_buffer; bufVec.push_back(some_buffer); } bufVec.back(); //buffer doesn''t work.

Cuando llama a push_back , copia some_buffer en un BufferObject en el vector . Entonces, justo antes de salir de ese ámbito, hay dos objetos BufferObject .

¿Pero qué objeto de tampón OpenGL almacenan? Bueno, almacenan el mismo . Después de todo, en C ++, simplemente copiamos un número entero. Entonces, ambos objetos C ++ almacenan el mismo valor entero.

Cuando some_buffer ese alcance, se destruirá some_buffer . Por lo tanto, llamará a glDeleteBuffers en este objeto OpenGL. Pero el objeto en el vector todavía tendrá su propia copia de ese nombre de objeto OpenGL. Que ha sido destruido .

Entonces ya no puedes usarlo; De ahí los errores.

Lo mismo sucede con su función InitBuffer . buff se destruirá después de que se copia en el valor de retorno, lo que hace que el objeto devuelto no tenga valor.

Todo esto se debe a una violación de la llamada "Regla de 3/5" en C ++. Creó un destructor sin crear copia / mover constructores / operadores de asignación. Eso es malo.

Para resolver esto, sus contenedores de objetos OpenGL deben ser de solo movimiento. Debe eliminar el constructor de copia y el operador de asignación de copia, y proporcionar equivalentes de movimiento que establezcan el objeto movido del objeto 0:

class BufferObject { private: GLuint buff_; public: BufferObject() { glGenBuffers(1, &buff_); } BufferObject(const BufferObject &) = delete; BufferObject &operator=(const BufferObject &) = delete; BufferObject(BufferObject &&other) : buff_(other.buff_) { other.buff_ = 0; } BufferObject &operator=(BufferObject &&other) { //ALWAYS check for self-assignment if(this != &other) { Release(); buff_ = other.buff_; other.buff_ = 0; } return *this; } ~BufferObject() {Release();} void Release(); { if(buff_) glDeleteBuffers(1, &buff_); } //Other members. };

Existen varias otras técnicas para hacer envoltorios RAII de solo movimiento para objetos OpenGL.