我有这样的事情:
class GLSLShader {
public:
GLSLShader(GLenum);
~GLSLShader();
};
class GLSLProgram {
public:
GLSLProgram(GLSLShader *, GLSLShader *);
~GLSLProgram();
private:
GLSLShader *m_VertexShader;
GLSLShader *m_FragmentShader;
};
将像这样调用GLSLProgram构造函数:
GLSLProgram program(new GLSLShader(GL_VERTEX_SHADER), new GLSLShader(GL_FRAGMENT_SHADER));
我的问题是我应该在哪里删除已分配的Shader对象。我应该在GLSLProgram的析构函数中删除它,还是应该用类似下面的代码来管理它?
GLSLShader *vertex = new GLSLShader(GL_VERTEX_SHADER);
GLSLShader *fragment = new GLSLShader(GL_FRAGMENT_SHADER);
GLSLProgram program(vertex, fragment);
delete vertex;
delete fragment;
答案 0 :(得分:2)
你有两个基本问题。
第一个问题是您正在错误地使用RAII对象。 RAII对象的要点是使用自动变量管理对象生存期,而不是明确使用new
和delete
。通过在new
上使用GLSLShader
,无需将指针包装到RAII容器中,您就可以有效地减轻析构函数的工作量。
您的GLSLProgram
构造函数不应该通过指针获取对象。它应该由const&
开始。这使调用者更容易决定这些对象应该持续多长时间。
第二个问题是合乎逻辑的。 GLSLProgram
没有理由负责销毁它所提供的着色器对象。这应该取决于调用代码,因为GLSL着色器对象可以重用。
因此,GLSLProgram
不应试图销毁这些对象。但是在成功创建程序之后,构造函数应该使用glDetachShader
从GLSL程序中分离GLSL着色器。
总的来说,你的代码应该是这样的:
GLSLShader vertex(GL_VERTEX_SHADER);
GLSLShader fragment(GL_FRAGMENT_SHADER);
//Fill `vertex` and `fragment` with actual shader code.
GLSLProgram program(vertex, fragment);
//Destructors for `vertex` and `fragment` will take care of themselves.
此外,您应该了解其他一些事项:
可以使用2个以上的着色器对象创建程序。所以你应该有可以使用许多这样的对象的替代构造函数。
Separable programs可以直接从字符串创建,而根本不使用着色器对象。
答案 1 :(得分:1)
我应该在GLSLProgram的析构函数中删除它还是应该以不同方式管理它
取决于。
GLSLProgram
以外的任何内容是否需要访问这些动态对象?这些对象可以比指向它们的GLSLProgram
实例更长吗?如果两者都是,那么内存不能仅由program
管理。
在任何一种情况下,如果将内存管理委托给仅负责破坏动态对象的RAII对象,您将发现编写正确的程序要容易得多。
另一方面,如果GLSLProgram
可以单独管理内存,那么肯定也应该分配它们。此外,似乎根本没有理由使用动态分配。我推荐使用成员对象,除非有特殊原因不这样做。
考虑到问题的尝试,我建议遵循:
class GLSLProgram {
public:
GLSLProgram():
m_VertexShader(GL_VERTEX_SHADER),
m_FragmentShader(GL_FRAGMENT_SHADER) {}
private:
GLSLShader m_VertexShader;
GLSLShader m_FragmentShader;
};