Scene结构有一个指向(SceneObjects的链接列表)的指针。 每个SceneObject都引用一个Mesh。 但是,某些SceneObject可以引用相同的Mesh(通过共享相同的指针 - 或句柄,稍后再看 - 到Mesh)。网格很大,这样做有明显的渲染速度优势。
typedef struct {
Mesh *mesh;
...
struct SceneObject *next;
} SceneObject;
typedef struct Scene {
SceneObject *objects;
...
} Scene;
我的问题: 如何释放场景,同时避免多次释放相同的网格指针?
我认为我可以通过使用句柄来使用Mesh (Mesh** mesh_handle)
而不是指针来解决这个问题,所以我可以将引用的Mesh指针设置为0,并让连续释放它只是释放0,但我无法制作这行得通。我无法理解如何避免多次解除分配。
我是否被迫为这种情况保留参考资料?或者我被迫将所有Mesh对象放入一个单独的Mesh表中并单独释放它?有没有办法解决这个问题而不做这些事情?通过将对象标记为彼此的实例,我可以自然地调整自由算法,以便处理问题,但我想知道是否有更“纯”的解决方案来解决这个问题。
答案 0 :(得分:1)
一个标准的解决方案是使用引用计数器,即许多其他对象可能引用的每个对象都必须有一个计数器,记住有多少对象指向它。这是通过类似
的方式完成的typedef struct T_Object
{
int refcount;
....
} Object;
Object *newObject(....)
{
Object *obj = my_malloc(sizeof(Object));
obj->refcount = 1;
....
return obj;
}
Object *ref(Object *p)
{
if (p) p->refcount++;
return p;
}
void deref(Object *p)
{
if (p && p->refcount-- == 1)
destroyObject(p);
}
首先分配对象的人将是第一个所有者(因此计数器初始化为1)。每次存储ref(p)
instad时需要将指针存储在其他位置时,一定要增加计数器。当有人不再指向它时,你应该致电deref(p)
。一旦对象的最后一次引用消失,计数器将变为零,deref调用将实际销毁该对象。
让它工作需要一些纪律(你应该总是在调用ref和deref时考虑)但是使用这种方法编写没有泄漏的复杂软件是可能的。
有时适用的更简单的解决方案是将所有共享对象也存储在单独的列表中...您可以自由地分配和更改指向这些对象的复杂数据结构,但在正常使用期间永远不会释放它们。只有当您需要抛弃所有内容时,才能使用该单独的列表释放这些对象。 请注意,只有在“正常使用”期间没有分配许多对象时才可以采用这种方法,因为在这种情况下延迟销毁可能是不可行的。