gpt4 book ai didi

c++ - 为什么在复制之前调用析构函数?

转载 作者:搜寻专家 更新时间:2023-10-31 00:10:06 26 4
gpt4 key购买 nike

我有以下代码

class Mesh
{
public:
Mesh();
Mesh(std::vector<Vertex> vertices, std::vector<GLuint> indices);
~Mesh();
void draw(Shader& shader);

private:
std::vector<Vertex> mVertices;
std::vector<GLuint> mIndices;
GLuint mVBO;
GLuint mEBO;
};

Mesh::Mesh(std::vector<Vertex> vertices, std::vector<GLuint> indices)
{
mIndices = indices;
glGenBuffers(1, &mEBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndices.size() * sizeof(GLuint), &mIndices[0], GL_STATIC_DRAW);

mVertices = vertices;
glGenBuffers(1, &mVBO);
glBindBuffer(GL_ARRAY_BUFFER, mVBO);
glBufferData(GL_ARRAY_BUFFER, mVertices.size() * sizeof(Vertex), &mVertices[0], GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

computeBoundingBox();
}

Mesh::~Mesh()
{
glDeleteBuffers(1, &mVBO);
glDeleteBuffers(1, &mEBO);
}

void Mesh::draw(Shader& shader)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEBO);
glBindBuffer(GL_ARRAY_BUFFER, mVBO);

GLuint vpos = glGetAttribLocation(shader.program(), "vPosition");
GLuint vnor = glGetAttribLocation(shader.program(), "vNormal");

glVertexAttribPointer(vpos, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(vnor, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)sizeof(Vector));

shader.bind();
glEnableVertexAttribArray(vpos);
glEnableVertexAttribArray(vnor);
glDrawElements(GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, 0);
shader.unbind();

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void loadSquare(Mesh& mesh)
{
std::vector<Vertex> vertices;
vertices.push_back(Vertex(Vector(0.5f, 0.5f, 0.f), Vector(1.f, 0.f, 0.f)));
vertices.push_back(Vertex(Vector(-0.5f, 0.5f, 0.f), Vector(0.f, 1.f, 0.f)));
vertices.push_back(Vertex(Vector(-0.5f, -0.5f, 0.f), Vector(0.f, 0.f, 1.f)));
vertices.push_back(Vertex(Vector(0.5f, -0.5f, 0.f), Vector(1.f, 0.f, 1.f)));

std::vector<GLuint> indices;
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
indices.push_back(0);
indices.push_back(2);
indices.push_back(3);

mesh = Mesh(vertices, indices);
}

int main(int argc, char** argv)
{
// Create opengl context and window
initOGL();

// Create shaders
Shader shader("render.vglsl", "render.fglsl");

Mesh mesh;
loadSquare(mesh);

while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

mesh.draw(shader);

glfwSwapBuffers(window);
glfwPollEvents();
}

glfwTerminate();
return 0;
}

如果我尝试运行它,它只会在它创建的窗口上显示一个灰色图像。

在使用调试器跟踪应用程序后,当它到达 mesh = Mesh(vertices, indices) 行时,它会为 OpenGL 创建缓冲区并将顶点和索引 std::vectors 复制到变量作为参数传递的 mesh。但是,它还会调用由 Mesh(vertices,indices) 创建的对象的析构函数,这反过来会使 OpenGL 上下文中的缓冲区无效,因此当应用程序到达 mesh.draw(shader) 指向的缓冲区网格点不再有效。

move-constructor 是否可以帮助我解决我的问题,即避免调用 Mesh(vertices,indices) 的析构函数?还有其他解决方案吗?

最佳答案

从您的来源来看,您正在绑定(bind)到立即销毁的 vector 。

本质上,在您的 loadSquare 函数中,当您在 loadSquare 最后一行的赋值右侧写入 Mesh(vertices, indices); 时,您正在创建一个网格并绑定(bind)它。

mesh = Mesh(vertices, indices);

像这样想那行:

  ...
Mesh m1(vertices, indices); // a
mesh= m1; // b
// m1 gets destroyed here.
}

(a) 行创建并绑定(bind)网格。

当您将它分配给 b 行中的网格时,mesh.mVertices 和 mesh.mIndices 将获得 vector 的拷贝,而 mVBO 和 mEBO 将获得绑定(bind)值的拷贝。

将 (b) 行视为写作

mesh.mVertices= m1.mVertices;  // mesh gets a new vector with the same values
mesh.mIndices= m1.mIndices; // mesh gets a new vector with the same values
mesh.mVBO= m1.mVBO;
mesh.mEBO= m1.mEBO;

在 loadSquare() 结束时,m1 将被销毁(调用析构函数)。

在您的调用函数中,您最终会得到包含绑定(bind)到被销毁 vector 的 mVBO 和 mEBO 成员的网格。它包含自己的 vector ,这些 vector 具有相同的值,但它们是不同内存位置中从未绑定(bind)的拷贝。

有多种方法可以解决这个问题,例如通过指针返回方形网格。或者编写赋值运算符(谷歌搜索浅拷贝)。

但我的建议是创建一个空的构造函数和一个额外的 fillMesh 函数,就像您当前的 cotstructor。

Mesh::Mesh(void);            // set mVBO and mEBO to zero.
void Mesh::fillMesh(std::vector<Vertex> vertices, std::vector<GLuint> indices); // same code as your current constructor.

然后像这样重写您的 loadSquare 函数:

void loadSquare(Mesh& mesh)
{
std::vector<Vertex> vertices;
vertices.push_back(Vertex(Vector(0.5f, 0.5f, 0.f), Vector(1.f, 0.f, 0.f)));
vertices.push_back(Vertex(Vector(-0.5f, 0.5f, 0.f), Vector(0.f, 1.f, 0.f)));
vertices.push_back(Vertex(Vector(-0.5f, -0.5f, 0.f), Vector(0.f, 0.f, 1.f)));
vertices.push_back(Vertex(Vector(0.5f, -0.5f, 0.f), Vector(1.f, 0.f, 1.f)));

std::vector<GLuint> indices;
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
indices.push_back(0);
indices.push_back(2);
indices.push_back(3);

mesh.fillMesh(vertices, indices);
}

因此 loadSquare 将创建顶点和索引并将它们从调用函数设置到网格中并绑定(bind)它们。

进一步说明(对于干净的解决方案):

  • 析构函数也应该从中解除 vector 和索引的绑定(bind)GL。
  • fillMesh 函数应该检查网格是否是在设置和绑定(bind)之前已经绑定(bind)和解除绑定(bind)旧 vector 新的(以防您在事件网格上再次调用 fillMesh)。
  • 您可能仍应编写调用 fillMesh 的赋值运算符:Mesh::operator=(const Mesh &other);//谷歌浅拷贝

关于c++ - 为什么在复制之前调用析构函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39904367/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com