在 C 中,RAII(资源获取即初始化)用于确保资源在使用时自动释放不再需要。此模式通常应用于 OpenGL 对象。然而,在为 OpenGL 对象实现 RAII 时有时会出现问题,导致它们停止工作。
尝试复制或移动 OpenGL 对象包装器时会出现这样的问题。默认情况下,C 生成一个复制构造函数,它只复制对象的成员。在 OpenGL 对象包装器的情况下,两个副本都将引用相同的 OpenGL 对象。
考虑以下代码:
// An OpenGL object wrapper with RAII class BufferObject { public: BufferObject() { glGenBuffers(1, &buff_); } ~BufferObject() { glDeleteBuffers(1, &buff_); } private: GLuint buff_; }; // Vector of buffer objects vector<BufferObject> bufVec; { BufferObject some_buffer; // Create buffer object // Initialize some_buffer // Copy some_buffer into the vector bufVec.push_back(some_buffer); } // Error: bufVec.back() will reference a deleted object // Function returning a buffer object BufferObject InitBuffer() { BufferObject buff; // Create buffer object // Do stuff with buff // Return a copy of buff return buff; } // Error: The returned buffer will reference a deleted object auto buff = InitBuffer();
在此示例中,将 some_buffer 的副本添加到 bufVec 并从 InitBuffer() 返回的缓冲区都引用相同的 OpenGL 对象。当 some_buffer 在其范围结束时被销毁时,它会删除 OpenGL 对象。这使得 buffVec.back() 和返回的缓冲区不可用,从而导致错误。
要解决此问题,OpenGL 对象包装器必须是仅移动类型。这可以通过以下方式实现:
BufferObject(const BufferObject &) = delete; BufferObject &operator=(const BufferObject &) = delete;
BufferObject(BufferObject &&other) : buff_(other.buff_) { other.buff_ = 0; } BufferObject &operator=(BufferObject &&other) { if (this != &other) { Release(); buff_ = other.buff_; other.buff_ = 0; } return *this; }
这些修改确保不会发生复制,以及 OpenGL 对象的所有权被移动而不是被复制。
以上是如何避免在 C RAII 中复制和移动 OpenGL 对象包装器时出现问题?的详细内容。更多信息请关注PHP中文网其他相关文章!