问题
Mesh类,包含vao/vbo/ibo这些OpenGL资源,包含了析构函数,在释放资源时候通过glDeleteBuffers 和 glDeleteVertexArrays销毁了这些资源。Mesh通过std::vector管理,添加Mesh使用了push_back或emplace_back,会导致不同的Mesh持有的vao/vbo/ibo一样。 几个问题:
- 析构后,vao/vbo/ibo应该设置成一个无效值
- std::vector没有分配足够内存,插入元素后,可能导致空间的重新分配,旧元素的拷贝或移动到新位置,旧元素内存析构掉。
- 一个OpenGL资源申请、释放、在申请,可能是同一个id
解决
- 提取分配足够空间
1
meshes.reserve(expectedCount);
- 实现移动构造函数并转移所有权
1
2
3
4
5
6
7
8
9
10
11
12
13
14// Mesh(const Mesh&) = delete;
// Mesh& operator=(const Mesh&) = delete;
Mesh(Mesh&& other) noexcept
: vao(other.vao), vbo(other.vbo), ibo(other.ibo) {
other.vao = 0;
other.vbo = 0;
other.ibo = 0;
}
~Mesh() {
if (vao != 0) glDeleteVertexArrays(1, &vao);
if (vbo != 0) glDeleteBuffers(1, &vbo);
if (ibo != 0) glDeleteBuffers(1, &ibo);
} - 智能指针
总结
无论是插入方式和构造函数,都有可能导致数据的重新分配,就必然会导致析构函数的调用。仅仅禁用拷贝构造或者赋值构造并不能解决问题,因为不能通过修改拷贝源(const&)的值来规避资源释放。