我在C类中有一个OpenGL对象。因为我正在使用RAII,所以我想让析构函数删除它。所以我的课看起来像:
class BufferObject
{
private:
GLuint buff_;
public:
BufferObject()
{
glGenBuffers(1, &buff_);
}
~BufferObject()
{
glDeleteBuffers(1, &buff_);
}
//Other members.
};
这似乎有效。但每当我执行以下操作时,我在使用OpenGL时就会出现各种错误:
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.
发生什么事?
注意:这是试图建立一个规范的答案,这些问题。
所有操作都复制缓冲区对象。但是由于你的类没有拷贝构造函数,它只是一个浅拷贝。由于析构函数删除缓冲区而不进一步检查,缓冲区将与原始对象一起删除。Nicol Bolas建议定义一个移动构造函数,删除复制构造函数和复制赋值操作符,我会描述一种不同的方式,这样两个缓冲区在复制后都可以使用。
您可以使用std::map
数组轻松跟踪有多少对象使用单个对象。考虑下面的示例代码,这是代码的扩展:
#include <map>
std::map<unsigned int, unsigned int> reference_count;
class BufferObject
{
private:
GLuint buff_;
public:
BufferObject()
{
glGenBuffers(1, &buff_);
reference_count[buff_] = 1; // Set reference count to it's initial value 1
}
~BufferObject()
{
reference_count[buff_]--; // Decrease reference count
if (reference_count[buff_] <= 0) // If reference count is zero, the buffer is no longer needed
glDeleteBuffers(1, &buff_);
}
BufferObject(const BufferObject& other) : buff_(other.buff_)
{
reference_count[buff_]++; // Increase reference count
}
BufferObject operator = (const BufferObject& other)
{
if (buff_ != other.buff_) { // Check if both buffer is same
buff_ = other.buff_;
reference_count[buff_]++; // Increase reference count
}
}
// Other stuffs
};
代码是相当自我解释的。初始化缓冲区对象时,将创建一个新的缓冲区。然后构造函数在reference\u count
数组中创建一个新元素,将缓冲区作为键,并将其值设置为1。每当复制对象时,计数都会增加。当对象被破坏时,计数减少。然后析构函数检查计数是否为0或更少,这意味着不再需要缓冲区,因此将删除缓冲区。
我建议不要将实现(或者至少是reference\u count
数组)放在头文件中,这样就不会生成链接器错误。
所有这些操作都复制C对象。因为您的类没有定义复制构造函数,所以您得到了编译器生成的复制构造函数。这只是复制对象的所有成员。
考虑第一个例子:
vector<BufferObject> bufVec;
{
BufferObject some_buffer;
//Initialize some_buffer;
bufVec.push_back(some_buffer);
}
bufVec.back(); //buffer doesn't work.
当您调用push_back
时,它会将一些缓冲区
复制到向量
中的缓冲区对象
。因此,在我们退出该范围之前,有两个BufferObject
对象。
但是他们存储了什么OpenGL缓冲区对象呢?嗯,它们都是一样的。毕竟,对于C,我们只是复制了一个整数。因此,两个C对象存储相同的整数值。
当我们退出该范围时,some_buffer
将被销毁。因此,它将在这个OpenGL对象上调用glDeleteBuffers
。但是向量中的对象仍然有它自己的OpenGL对象名称副本。已经被摧毁了。
所以你不能再使用它了;因此出现了错误。
InitBuffer
函数也会发生同样的情况buff
复制到返回值后将被销毁,这使得返回的对象毫无价值。
这都是因为违反了C中所谓的“3/5规则”。创建析构函数时没有创建复制/移动构造函数/赋值操作符。那很糟糕。
为了解决这个问题,您的OpenGL对象包装器应该是只移动类型。您应该删除复制构造函数和复制赋值操作符,并提供将move-from对象设置为对象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包装器还有各种其他技术。
所以我有一个立方体,我想绕着它的三个轴(立方体的轴,而不是窗口)旋转。正如许多其他类似的问题所指出的,只要我只朝一个方向旋转,我的旋转就会起作用,但当我开始混合它们时,我会得到奇怪的结果。特别是,无论立方体如何旋转,围绕y轴的旋转始终围绕窗口的y轴旋转。 我的绘图代码如下: 这个问题似乎非常准确地描述了我想做什么,公认的答案似乎是我想做什么,但是他提供的链接已经死了。 从我在链接问题中收集到的信息
我正在开发一些游戏,以便学习OpenGL。 我正在尝试实现一种方法来拾取对象(例如,镐、枪等)。 这个想法是,即使在相机移动或旋转之后,这个物体也会固定在相机前面。 当我向前、向后、向左、向右、向上或向下移动时,我可以通过在相机正前方设置对象的位置来使对象跟随我。 然而...当相机旋转/倾斜(向上、向下、向左、向右看...)问题就开始了。 在这种情况下,一切都很好(向上、向下、向左、向右、向右倾斜
我有一个奇怪的问题,每天我的AJAX请求一个网站不再工作。 我现在正在努力使它工作,但找不到问题。 这是我的JavaScript:基本上它非常简单,它检索ip adres并将其发送到存储它的站点。 在服务器上,我现在添加了这一项,以避免使用通配符 当我只使用 头('access-control-allow-origin:');我得到错误:Cross-Origin-request blocked:C
我在Android Studio工作,多年来一直在正常模式和调试模式下愉快地运行。突然,调试模式对我来说停止了工作。 如果我尝试单击调试按钮(带有“播放”三角形的小错误),它会尝试在模拟器中启动,但应用程序永远不会打开。 在模拟器上,我得到了“等待调试器”的警告,以及“强制关闭”的选项。在Android Studio本身,底部的调试窗口反复显示“等待应用程序上线:”然后“无法连接到远程进程。正在中
考虑下面的代码: 对于上面的代码,输出是:
我使用Java和OpenGL(LWJGL)来设置一些矩阵,我不想使用内置的方法,因为我也想在Android上工作,所以使用LWJGL的矩阵类是不合适的。目前我正在建立一个透视图,使用一个视场70,znear 0.1,zfar 1000。使用当前设置旋转只会导致奇怪的结果,不是以正确的方式旋转,对象被奇怪地缩放,经常消失。 下面是Matrix4D类: 下面是Matrix类(用于在矩阵上设置和执行计算