【问题标题】:Recursively freeing C structs递归释放 C 结构体
【发布时间】:2009-06-03 01:14:56
【问题描述】:

我有一个结构,它只包含指向我分配的内存的指针。有没有办法递归地释放作为指针的每个元素,而不是在每个元素上调用 free?

例如,假设我有这样的布局:

typedef struct { ... } vertex;
typedef struct { ... } normal;
typedef struct { ... } texture_coord;

typedef struct
{
    vertex* vertices;
    normal* normals;
    texture_coord* uv_coords;
    int* quads;
    int* triangles;
} model;

在我的代码中,我 malloc 每个结构来创建一个模型:

model* mdl = malloc (...);
mdl->vertices = malloc (...);
mdl->normals = malloc (...);
mdl->uv_coords = malloc (...);
mdl->quads = malloc (...);
mdl->triangles = malloc (...);

这样释放每个指针很简单:

free (mdl->vertices);
free (mdl->normals);
free (mdl->uv_coords);
free (mdl->quads);
free (mdl->triangles);
free (mdl);

有没有一种方法可以递归地遍历 mdl 中的指针,而不是在每个元素上调用 free?

(在实践中,只为每个人编写 free() 几乎没有任何工作,但它会减少代码重复并有助于学习)

【问题讨论】:

    标签: c struct malloc


    【解决方案1】:

    并非如此 - 尽管您可以编写一个方法来完成所有六个释放操作,这样您就不会错过任何一个。

    void freeModel( model* md1 ) {
        free (mdl->vertices);
        free (mdl->normals);
        free (mdl->uv_coords);
        free (mdl->quads);
        free (mdl->triangles);
        free (mdl);
    }
    

    【讨论】:

      【解决方案2】:

      C 没有内置这样的功能,但你可以通过滥用宏预处理器来作弊:

      #define XX_MODEL_POINTERS do { \
        xx(vertices); xx(normals); xx(uv_coords); xx(quads); xx(triangles); \
      } while(0)
      

      分配:

      model *mdl = malloc(sizeof(*mdl));
      assert(mdl);
      #define xx(N) mdl->N = malloc(sizeof(*mdl->N)); assert(mdl->N)
      XX_MODEL_POINTERS;
      #undef xx
      

      免费:

      assert(mdl);
      #define xx(N) free(mdl->N); mdl->NULL
      XX_MODEL_POINTERS;
      #undef xx
      free(mdl);
      mdl = NULL;
      

      令人讨厌的是struct model 的定义和XX_MODEL_POINTERS 的定义可能会变得相互不一致,并且无法捕捉它。因此,通常最好通过在某处解析 .h 文件来生成 XX_MODEL_POINTERS 的定义。

      用 C 语言进行元编程绝非易事。

      【讨论】:

      • 好聪明,谢谢!虽然这个解决方案看起来确实很脏,但它避免了代码重复而没有性能损失,而且这是我以前从未见过的方法。我可能不会在实践中使用它,但它通过一个有趣的实现解决了我的问题,而不仅仅是重新组织代码。
      • 难道您不能进行操作以执行宏的参数,而不必每次都重新#define它吗?
      • 我认为你在这里滥用了“滥用”这个词。像这样的东西就是预处理器的用途,我想!滥用 -> 使用 :)
      【解决方案3】:

      C 语言没有办法做到这一点,也不可取 - C 不知道每个成员都是通过 malloc 分配的不同指针,并且 C 不包含执行此操作的运行时类型信息支持 -在运行时,访问该结构的编译代码只是为每个成员访问使用基指针的偏移量。

      最简单的方法是编写一个“FreeModel”函数:

      void FreeModel(model* mdl)
      {
         free(mdl->vertices);
         ... // Other frees
         free(mdl);
      }
      

      【讨论】:

        【解决方案4】:

        如果您这样做,请查看talloc http://talloc.samba.org/

        model* mdl = talloc (NULL, ...);
        mdl->vertices = talloc (mdl, ...);
        mdl->normals = talloc (mdl, ...);
        mdl->uv_coords = talloc (mdl, ...);
        mdl->quads = talloc (mdl, ...);
        mdl->triangles = talloc (mdl, ...);
        

        然后你可以:

        talloc_free(mdl);
        

        talloc 将处理free'ing 所有其他您调用talloc 的块,mdl 作为分配时的第一个参数(它会递归地执行此操作,您可以执行talloc(mdl->vertices, ...)talloc_free(mdl); 也会得到)

        顺便说一句,使用talloc 有一点开销,因为它需要跟踪递归的内容,但不是很多。

        【讨论】:

          【解决方案5】:

          你可以一起计算所有这些所需的大小,然后做一个大的 malloc

          sizeof(model)+sizeof(vertex)*nVertices...等

          将结果赋值给mdl,result+sizeof(model)赋值给model->vertices...

          然后释放它只是一个免费的。

          您可能不得不担心对齐问题(取决于您的平台),但这并不难解决。另一个问题是它是一个更大的块,如果在内存受限的环境中可能会出现问题。

          【讨论】:

            【解决方案6】:

            把所有的free都扔到一个函数里?

            【讨论】:

              【解决方案7】:

              不相信这在任何形式的 C 中都是可能的。

              您可以为该特定结构编写一个单独的函数,您可以在其中传递指针并在那里释放它们。

              编辑:Ups,太晚了,从来没有看到那些答案......

              【讨论】:

                【解决方案8】:

                不适用于那些结构。您可以将另一个条目添加到包含要释放的指针列表的顶级“模型”结构中,然后迭代该列表。但我怀疑该解决方案增加的复杂性和降低的可理解性是否值得。 (除非您在顶级“模型”结构中释放的条目集比您在此处显示的要大得多且嵌套更深。)

                【讨论】:

                  猜你喜欢
                  • 2018-01-17
                  • 2016-04-13
                  • 1970-01-01
                  • 2015-01-05
                  • 2012-11-15
                  • 2010-09-30
                  • 2021-07-30
                  • 2012-07-20
                  • 2011-07-25
                  相关资源
                  最近更新 更多