应删除传递参数时创建对象的位置

Where objects created when passing parameters should be deleted?

本文关键字:创建对象 位置 参数 删除      更新时间:2023-10-16

我有类似的东西:

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

我的问题是我应该在哪里删除分配的着色器对象。我应该在GLSLPROGRAM的破坏器上删除它,还是应该使用以下代码之类的内容进行不同的管理?

GLSLShader *vertex = new GLSLShader(GL_VERTEX_SHADER);
GLSLShader *fragment = new GLSLShader(GL_FRAGMENT_SHADER);
GLSLProgram program(vertex, fragment);
delete vertex;
delete fragment;

您有两个基本问题。

第一个问题是您错误地使用了RAII对象。RAII对象的点是使用自动变量来管理对象寿命,而不是明确使用newdelete。通过在GLSLShader上使用new,而无需将该指针包装到RAII容器中,您就可以有效地减轻攻击者的作用。

您的GLSLProgram构造函数不应通过指针采用对象。它应该将它们带到const&。这使呼叫者更容易决定这些对象应该持续多长时间。

第二个问题是合乎逻辑的。GLSLProgram没有理由负责其给出的着色器对象的破坏。这应该取决于调用代码,因为GLSL着色器对象可以是重复使用

因此,GLSLProgram不应尝试摧毁这些对象。但是成功创建程序后,构造函数应使用glDetachShader

总的来说,您的代码应该看起来像这样:

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. 可以直接从字符串中创建可分离程序,而无需使用着色器对象。

我应该在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;
};