类设计:如何返回shared_ptr:引用或复制

时间:2013-01-30 15:25:23

标签: c++ memory-management shared-ptr opengl-2.0

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

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

  1. 创建着色器对象;
  2. 复制它;
  3. 销毁副本。
  4. 原始副本也会失效,因为当副本被销毁时,它会调用glDeleteShader。我相信这是一个设计问题。

    所以我通过使用指针避免了这个问题。现在,Program类包含着色器。我创建了一个方法,将shared_ptr返回到顶点,几何和片段Shader对象。我的疑问是:我应该像这样返回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 个答案:

答案 0 :(得分:5)

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

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

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

const Shader* getVertex_shader_ptr() const ...

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

shared_ptr<Shader> getVertex_shader_ptr() const ...

答案 1 :(得分:2)

无论哪种方式都可以。

它是一个成员,所以只要调用者没有通过引用保存它就可以安全地返回对它的引用,然后销毁Program

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

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

编辑:假设您在复制Program(而不是Shader)时担心正确性,请不要担心;这两个Program会将shared_ptrs放到同一个Shader中,直到Program为止都不会被销毁。这可能是您想要的,也可能不是(您可能希望在副本上分配完全独立的Shader),但它是安全的。

答案 2 :(得分:2)

我更愿意按价值回报。如果通过引用返回,则可能会遇到对shared_ptr的悬空引用,如果在某个时刻实例被销毁并且某些变量仍保留对shared_ptr的引用。

这种情况正是智能指针应该避免的情况,但是如果您避免通过复制返回它们,它们的引用计数只能安全地工作。这将使在此使用shared_ptr的整个过程无效。

答案 3 :(得分:1)

在不了解底层共享指针问题的情况下,我发现Thiago Macieira(可能是Qt / Trolltech员工)的这篇文章对于更好地了解是否返回值或const&:{ {3}}

从该帖子引用,这是从const函数返回值的核心参数:

  

原因是:

T at(const Key& k) const;
     

而不是:

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

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

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