C++破坏者奇怪的行为

C++ destructor weird behavoiur

本文关键字:破坏者 C++      更新时间:2023-10-16

我有一个模型类,其中包含模型绘制的缓冲区,它的实现如下所示:

Model::Model(std::vector<Vertex> vertices, std::vector<short> indices)
{
    mVertices = vertices;
    mIndices = indices;
    mMatrix = glm::mat4(1.0f);
    mIsTextured = false;
    Initialize();
}
Model::~Model()
{
    glDeleteBuffers(1, &mVertexBuffer);
    glDeleteBuffers(1, &mIndiceBuffer);
}
void Model::Initialize()
{
    glGenBuffers(1, &mVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*mVertices.size(), &mVertices[0], GL_STATIC_DRAW);
    glGenBuffers(1, &mIndiceBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndiceBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*mIndices.size(), &mIndices[0], GL_STATIC_DRAW);
}

现在我在析构函数中遇到了一个非常奇怪的问题,我像这样使用这个类:

Renderer *renderer = new Renderer();
Model m = parseSKNFromFile("model.skn");
m.ApplyTexture(textureID);
while (!glfwWindowShouldClose(window))
{
    update();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    renderer->RenderModel(&m);
    glfwSwapBuffers(window);
    glfwPollEvents();
}

以这种方式使用 Model 类会触发运行时访问冲突读取位置错误,但如果我在构造函数中注释 glDeleteBuffers 调用,则所有工作都会找到。看起来不知何故,那些删除函数突然被调用,我不知道如何以及为什么。

这也是 RenderModel 函数:

mShader.bind();
glm::mat4 MVP = mProjection * glm::lookAt(glm::vec3(0, 100, 200), glm::vec3(0, 100, 0), glm::vec3(0, 1, 0)) * model->GetMatrix();
glUniformMatrix4fv(mShader.getUniformLocation("MVP") , 1, GL_FALSE, &MVP[0][0]);
if (model->IsTextured())
{
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, model->GetTexture());
    glUniform1i(model->GetTexture(), 0);
}
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, model->GetVertexBuffer());
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);  //float position[3]
glVertexAttribPointer(1, 1, GL_INT, GL_FALSE, sizeof(Vertex), (void*)12);    //char boneIndex[4]
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)16); //float weights[4]
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)32); //float normals[3]
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)44); //float textureCords[2]
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->GetIndiceBuffer());
glDrawElements(GL_TRIANGLES, model->GetIndiceSize(), GL_UNSIGNED_SHORT, (void*)0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);

假设:您没有(不能有)正确的复制构造函数/赋值运算符。

因此:

private;
Model(const Model&); // No copy
Model& operator = (const Model&); // No copy

由于您正在创建 Model 的内联对象,因此当它超出范围时,它将自动销毁,并且该范围位于您实例化渲染器的函数的末尾。

我建议将模型更改为堆分配的对象,并在释放渲染器和销毁窗口之前手动销毁它。

Model* m = parseSKNFromFile( "model.skn" );

我还会提出一些其他建议,例如将索引和顶点数组作为模型构造函数中的常量引用。此外,我认为从对象的析构函数调用 gl 命令不是一个好主意,最好将这种类型的功能分开以分离模型中的函数,也不初始化构造函数中的 OpenGL 缓冲区。这样做的原因是,如果您想将对象分配与渲染器初始化分开,以便您可以将它们加载到与渲染线程不同的线程上。