首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在这种情况下,如何正确使用RAII /减少内存泄漏

在这种情况下,如何正确使用RAII /减少内存泄漏
EN

Stack Overflow用户
提问于 2013-02-24 20:37:22
回答 3查看 226关注 0票数 2

在这种情况下,我不知道如何才能充分利用RAII。情况是这样的:

我正在创建一个基本的渲染器。几何图形由Geometry类描述,该类可能添加了顶点。为了使Geometry对象用于渲染,必须首先编译它(即,将为Geometry创建一个VBO )。geometery对象的合并(和解压)是通过Renderer对象完成的,反编译必须在geometery对象完成后才能完成。如果不做反编译,就会有内存泄漏。

下面是我所描述的一个例子:

代码语言:javascript
运行
复制
Renderer renderer; // the renderer object

{
    Geometry geometry;

    // add vertices
    // and play around with material, etc.

    if(!renderer.compile(geometery); // compile the geometery, so we can use it
    {
        cerr << "Failed to compile geometry!\n";
    }

    // now we can use it...
    renderer.render(geometry, RenderType::TriangleStrips);

} // if I don't call renderer.decompile(geometry) here, I will get a leak

我想要做的是反编译我的几何模型,而不是显式地告诉渲染器反编译它。这只是为了减少内存泄漏。我的第一个想法是使用RAII,但如果我这样做,Geometry类将需要Renderer类,这看起来相当混乱。因为我需要一个对Renderer对象的引用,该对象编译了geometery。

我想到的另一种选择是让渲染器创建几何图形,但这将导致几何对象动态分配(即使用new),而且看起来也很混乱。

我还考虑在几何图形中放置一个句柄对象,例如指向抽象句柄对象的unique_ptr。

例如:

代码语言:javascript
运行
复制
class GeometeryHandle
{
   virtual ~GeometeryHandle() = 0; 
};

这实际上可能会起作用,因为它还可以用于在句柄内存储GLuint。我不确定这是否合适,因为我可以直接通过渲染器引用来反编译几何图形。也就是说,如果我直接通过析构函数调用它,它也会做同样的事情。

我应该如何恰当地设计它,这样我才不会意外地没有反编译几何图形?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-02-24 21:12:39

不清楚谁应该对你设计中的内容负责。这是弄清楚如何使用任何形式的资源管理的第一步:决定谁对什么负责。

例如,您可以说"Geometry是由Geometry类描述的,这个类可能添加了顶点。“好的,但是这与编译后的数据有什么关系呢?如果用户在Geometry编译后向其添加顶点,这些顶点是否会自动放置在编译后的数据中?或者编译后的数据与Geometry类完全分开,这样对Geometry类的更改不会更新编译后的数据?

在我看来,你好像把两种截然不同的想法混为一谈了:GeometryBuilderRenderableGeometryBuilder是将顶点数据放入其中的对象。然后你用它来创建一个RenderableRenderable是存储在GeometryBuilder中的数据的优化形式。该对象完全独立于创建它的GeometryBuilderRenderable是您可以实际渲染的对象。

所以你会这样做:

代码语言:javascript
运行
复制
GeometryBuilder meshBuilder;

meshBuilder.AddVertex(...);
...

Renderable renderMesh = render.CreateRenderable(meshBuilder);

在此之后,meshBuilder将独立于renderMesh。你可以删除一个,另一个就可以了。您可以多次“编译”renderMesh,并获得相同数据的相同副本。以此类推。

票数 3
EN

Stack Overflow用户

发布于 2013-02-24 21:00:31

方法1:

您可以使用帮助器类:

代码语言:javascript
运行
复制
class CompileHandler
{
    private:
        Geometry& g;
        Renderer& r;
    public:
        CompileHandler(Geometry& _g, Renderer& _r) : g(_g), r(_r) 
        {
        }
        ~CompileHandler()
        {
            r.decompile(g);
        }
};

您可以通过以下方式使用它:

代码语言:javascript
运行
复制
{
    Geometry geometry;
    CompileHandler ch(geometry,renderer);

    // add vertices
    // and play around with material, etc.

    if(!renderer.compile(geometery); // compile the geometery, so we can use it
    {
        cerr << "Failed to compile geometry!\n";
    }

    // now we can use it...
    renderer.render(geometry, RenderType::TriangleStrips);
// decompilation is automatic on destruction of the CompileHandler object
}

方法二:

创建更强大的层次结构:

代码语言:javascript
运行
复制
GeometryCompiler
   ^
   |
   | inherits
   |
Renderer

在编译几何图形时,几何图形编译器(这里是渲染器)通知几何图形它已被编译(并将几何图形内部的GeometryCompiler指针设置为编译器)。然后,在销毁几何图形时,如果指针不为空,则可以要求GeometryCompiler对其进行反编译。

票数 3
EN

Stack Overflow用户

发布于 2013-02-24 21:08:46

RAII要求dstructor执行“撤销”操作。

在这种情况下,几何体被破坏,但渲染仍然存在。你唯一的触发器是Geometry析构函数,它应该知道render编译了什么,来调用他进行反编译。

但是,由于了解rederes并不是几何的目的,您很可能需要一个助手类(让我们称之为Compile_guard),它应该在几何完成后立即实例化,将geometry和Render作为参数,并在构造时调用Render::compile,在销毁时调用Render::反编译:

代码语言:javascript
运行
复制
Renderer renderer; // the renderer object

{
    Geometry geometry;

    // add vertices
    // and play around with material, etc.

    Compile_guard guard(render, geometry);

    if(!guard); // Invalid compilation ....
    { 
        cerr << "Failed to compile geometry!\n";
        return; // this is exception safe!
    }

    // now we can use it...
    renderer.render(geometry, RenderType::TriangleStrips);

} //here guard will decompile

关于Compile_guard,它可以是这样的

代码语言:javascript
运行
复制
class Compile_guard
{
public:
   Compile_guard(Render& r, Geometry& g) :render(&r), geometry(&g), good(false)
   { good = render->compile(*geometry); }

   ~Compile_guard()
   { if(good) render->decompile(*geometry); }

   explicit operator bool() const { return good; }

   Compile_guard(const Compile_guard&) =delete;  //just avoid copy and assign.
   Compile_guard& operator=(const Compile_guard&) =delete;
private:
   Render* render;
   Geometry* geometry;
   bool good;
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15051795

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档