应该删除传递参数时创建的对象?

时间:2016-06-28 13:39:25

标签: c++ opengl memory

我有这样的事情:

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;

2 个答案:

答案 0 :(得分:2)

你有两个基本问题。

第一个问题是您正在错误地使用RAII对象。 RAII对象的要点是使用自动变量管理对象生存期,而不是明确使用newdelete。通过在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.

此外,您应该了解其他一些事项:

  1. 可以使用2个以上的着色器对象创建程序。所以你应该有可以使用许多这样的对象的替代构造函数。

  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;
};