RAII avec les objets OpenGL en C : Comprendre les problèmes cachés
En programmation orientée objet C, l'acquisition de ressources est l'initialisation (RAII) est une technique utilisée pour gérer efficacement les ressources. Lors de l'utilisation d'objets OpenGL dans des classes C, il est courant de vouloir utiliser RAII pour garantir que l'objet OpenGL est correctement libéré lorsque la classe est détruite.
Considérez l'extrait de code suivant :
class BufferObject { private: GLuint buff_; public: BufferObject() { glGenBuffers(1, &buff_); } ~BufferObject() { glDeleteBuffers(1, &buff_); } };
Cette classe semble implémenter correctement RAII pour les objets OpenGL. Cependant, des problèmes surviennent lorsque la classe est copiée ou déplacée, comme en témoigne le code suivant :
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.
Dans ces scénarios, les objets OpenGL deviennent inutilisables, entraînant des erreurs.
La raison car ce comportement réside dans les constructeurs de copie par défaut et les opérateurs d'affectation générés par le compilateur. Ces opérations copient simplement les membres de l'objet, ce qui entraîne plusieurs objets C référençant le même objet OpenGL sous-jacent. Lorsque l'objet C d'origine est détruit, il libère l'objet OpenGL, obligeant les autres objets à référencer une ressource détruite.
Pour résoudre ce problème, la classe BufferObject doit être de type déplacement uniquement. Cela signifie éliminer le constructeur de copie et l'opérateur d'affectation et fournir des équivalents de déplacement qui transfèrent la propriété de l'objet OpenGL au nouvel objet.
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. };
Avec ces changements, la classe garantit que l'objet OpenGL est correctement géré et libéré, même lors de la copie ou du déplacement de la classe.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!