C++ C++;析构函数异常行为

C++ C++;析构函数异常行为,c++,opengl,C++,Opengl,我有一个模型类,其中包含模型要绘制的缓冲区,其实现如下所示: Model::Model(std::vector<Vertex> vertices, std::vector<short> indices) { mVertices = vertices; mIndices = indices; mMatrix = glm::mat4(1.0f); mIsTextured = false; Initialize(); } Model::

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

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();
}
以这种方式使用模型类会触发运行时访问冲突读取位置错误,但如果我在构造函数内注释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* m = parseSKNFromFile( "model.skn" );

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

正如我给出的第二个代码中所示,对象的分配在使用对象的同一个函数中(在本例中为main()函数),这仍然没有任何意义,因为如果我从析构函数中注释掉这些命令,一切都正常工作。另一方面,如果您有任何使用OpenGL编程OOP的资源,请在此处提供:DDo不要忘记三条规则:您是否有复制构造函数和复制赋值操作符?这一行很可能是您问题的根源:
Model m=parseSKNFromFile(“Model.skn”)。如果您编写
parseSKNFromFile(…)
以返回指向堆上分配的对象的指针,而不是创建副本,那么许多麻烦就会消失。