1

这是场景:我有一个名为 Program 的类,它包含三个 shared_ptr:到顶点、几何和片段着色器。当 Shader 对象被构造时,它会使用 glCreateShader 创建着色器,并且还会编译它。

Shader denstructor 会自动调用 glDeleteShader。所以问题是,如果我执行以下操作:

  1. 创建着色器对象;
  2. 复制它;
  3. 销毁副本。

原始副本也会失效,因为当副本被销毁时,它会调用 glDeleteShader。我相信这是一个设计问题。

所以我只使用指针就避免了这个问题。现在 Program 类拥有着色器。我创建了一个将 shared_ptr 返回给顶点、几何和片段着色器对象的方法。我的疑问是:我应该像这样返回 shared_ptr 吗:

const shared_ptr<Shader>& getVertex_shader_ptr() const
{
    return vertex_shader_ptr;
}

或者像这样:

shared_ptr<Shader> getVertex_shader_ptr() const
{
    return vertex_shader_ptr;
}

我担心我上面描述的问题会再次发生:shared_ptr 被释放并且它使 OpenGL 着色器无效。

4

4 回答 4

5

除非您的着色器为 NULL 有效,否则您应该只返回对它的引用:

const Shader& getVertex_shader() const
{
    return vertex_shader;
}

如果您的着色器为 NULL 是有效的,但只有您的程序负责删除它,则只需返回一个指针:

const Shader* getVertex_shader_ptr() const ...

共享指针的语义适用于着色器没有明确所有权的情况。如果是这种情况,则按值返回。语义是程序的两个部分对未清理的对象感兴趣,并且它们都需要一种方法来保持它的活力。

shared_ptr<Shader> getVertex_shader_ptr() const ...
于 2013-01-30T15:42:20.417 回答
2

无论哪种方式都很好。

它是一个成员,因此返回对它的引用是安全的,只要调用者不通过引用保存它,然后销毁Program.

如果您通过非常量引用返回,则调用者可以调用reset您的指针,glDeleteShader如果不存在指针的其他副本,该指针将调用。尽管如此,它会按照你的意愿行事——Shader只有在不再存在对它的引用时才会被销毁。

我个人会shared_ptr按价值返回,但这只是个人喜好。

编辑:假设您的意思是您在复制 a Program(而不是 a Shader)时担心正确性,也不要担心;这两个Programs 将具有相同的 shared_ptrs ,直到两个s 都Shader不会被销毁。Program这可能是也可能不是您想要的(您可能想要分配一个完全独立Shader的副本),但它是安全的。

于 2013-01-30T15:33:03.200 回答
2

我宁愿按价值返回。如果您通过引用返回,您可能会遇到对 shared_ptr 的悬空引用,如果在某个时候实例被销毁并且某些变量仍然持有对 shared_ptr 的引用。

这种情况正是智能指针应该避免的,但它们的引用计数只有在你避免通过复制返回它们时才能安全地工作。这将使在此处使用 shared_ptr 的全部意义无效。

于 2013-01-30T15:38:09.530 回答
1

在不太了解底层共享指针问题的情况下,我发现 Thiago Macieira(可能是 Qt/Trolltech 员工)的这篇文章对于更好地了解是返回值还是返回 a 很有帮助:http const&: //lists.trolltech.com /qt-interest/2007-11/thread00209-0.html

引用那篇文章,这是从const函数返回值的核心参数:

它的原因是:

T at(const Key& k) const;

代替:

const T &at(const Key &k) const;

是因为在 Qt 中到处都是这样。我们不会在任何地方返回 refs-to-const。为了返回一个 ref-to-const,我们需要一个变量存在于某处,这要求类的内部结构。通过返回一个值,我们可以在内部做任何我们想做的事情。

不过,我不确定,如果这适用于您的问题...(仍在学习自己;))

于 2013-01-30T15:59:20.680 回答