3 回答
TA贡献1801条经验 获得超16个赞
所有这些操作都复制C ++对象。由于您的类未定义副本构造函数,因此您将获得编译器生成的副本构造函数。这只是复制对象的所有成员。
考虑第一个示例:
vector<BufferObject> bufVec;
{
BufferObject some_buffer;
//Initialize some_buffer;
bufVec.push_back(some_buffer);
}
bufVec.back(); //buffer doesn't work.
当你调用push_back,它复制some_buffer到一个BufferObject在vector。因此,在退出该范围之前,有两个BufferObject对象。
但是它们存储什么OpenGL缓冲区对象?好吧,它们存储相同的一个。毕竟,对于C ++,我们只是复制了一个整数。因此,两个C ++对象都存储相同的整数值。
当我们退出该范围时,some_buffer将被销毁。因此,它将调用glDeleteBuffers此OpenGL对象。但是向量中的对象仍将具有其自己的OpenGL对象名副本。其中已被摧毁。
因此,您不能再使用它;因此错误。
InitBuffer函数也会发生同样的事情。buff复制到返回值后将被销毁,这使返回的对象变得毫无价值。
这都是由于违反了C ++中所谓的“ 3/5规则”。您创建的析构函数没有创建复制/移动构造函数/赋值运算符。那很糟。
为了解决这个问题,您的OpenGL对象包装器应为仅移动类型。您应该删除复制构造函数和复制分配运算符,并提供将从其移动的对象设置为对象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.
};
还有许多其他技术可为OpenGL对象制作仅移动RAII包装。
- 3 回答
- 0 关注
- 451 浏览
添加回答
举报