OpenGL object in C++ RAII class no longer works(C++ RAII 类中的 OpenGL 对象不再有效)
问题描述
我在 C++ 类中有一个 OpenGL 对象.因为我正在使用 RAII,所以我想让析构函数删除它.所以我的课程看起来像:
I have an OpenGL object in a C++ class. Since I'm employing RAII, I want to have the destructor delete it. So my class looks something like:
class BufferObject
{
private:
GLuint buff_;
public:
BufferObject()
{
glGenBuffers(1, &buff_);
}
~BufferObject()
{
glDeleteBuffers(1, &buff_);
}
//Other members.
};
这似乎有效.但是每当我执行以下任何操作时,我都会在使用它时遇到各种 OpenGL 错误:
This seems like it works. But any time I do any of the following, I start getting various OpenGL errors when I use it:
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.
怎么回事?
注意:这是为这些问题建立规范答案的尝试.
Note: this is an attempt to build a canonical answer to these questions.
推荐答案
所有这些操作都复制 C++ 对象.由于您的类没有定义复制构造函数,因此您将获得编译器生成的复制构造函数.这只是复制对象的所有成员.
All of those operations copy the C++ object. Since your class did not define a copy constructor, you get the compiler-generated copy constructor. This simply copies all of the members of the object.
考虑第一个例子:
vector<BufferObject> bufVec;
{
BufferObject some_buffer;
//Initialize some_buffer;
bufVec.push_back(some_buffer);
}
bufVec.back(); //buffer doesn't work.
当您调用push_back
时,它会将some_buffer
复制到vector
中的BufferObject
中.因此,在我们退出该作用域之前,有两个 BufferObject
对象.
When you call push_back
, it copies some_buffer
into a BufferObject
in the vector
. So, right before we exit that scope, there are two BufferObject
objects.
但是它们存储什么 OpenGL 缓冲区对象?好吧,它们存储相同的.毕竟,对于 C++,我们只是复制了一个整数.所以两个 C++ 对象都存储相同的整数值.
But what OpenGL buffer object do they store? Well, they store the same one. After all, to C++, we just copied an integer. So both C++ objects store the same integer value.
当我们退出该作用域时,some_buffer
将被销毁.因此,它将在此 OpenGL 对象上调用 glDeleteBuffers
.但是向量中的对象仍然有自己的那个 OpenGL 对象名称的副本.哪个已经被摧毁.
When we exit that scope, some_buffer
will be destroyed. Therefore, it will call glDeleteBuffers
on this OpenGL object. But the object in the vector will still have its own copy of that OpenGL object name. Which has been destroyed.
所以你不能再使用它了;因此出现错误.
So you can't use it anymore; hence the errors.
同样的事情发生在你的 InitBuffer
函数上.buff
复制到返回值后会被销毁,导致返回的对象一文不值.
The same thing happens with your InitBuffer
function. buff
will be destroyed after it is copied into the return value, which makes the returned object worthless.
这都是因为违反了C++中所谓的3/5法则".您创建了一个析构函数,而没有创建复制/移动构造函数/赋值运算符.这很糟糕.
This is all due to a violation of the so-called "Rule of 3/5" in C++. You created a destructor without creating copy/move constructors/assignment operators. That's bad.
要解决这个问题,您的 OpenGL 对象包装器应该是仅移动类型.您应该删除复制构造函数和复制赋值运算符,并提供将移动对象设置为对象 0 的移动等效项:
To solve this, your OpenGL object wrappers should be move-only types. You should delete the copy constructor and copy assignment operator, and provide move equivalents that set the moved-from object to object 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 包装器.
There are various other techniques for making move-only RAII wrappers for OpenGL objects.
这篇关于C++ RAII 类中的 OpenGL 对象不再有效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:C++ RAII 类中的 OpenGL 对象不再有效
基础教程推荐
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 从 std::cin 读取密码 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01