首页 > 解决方案 > C 内存管理约定:通过在堆栈上分配的对象释放在堆上分配的内存

问题描述

我想我对 C 中的内存管理约定有点困惑。

假设我们有一个在堆上动态分配数据的结构。此结构提供用于在堆上分配_alloc()_free()释放此结构的功能。

这是一个带有简单向量结构的示例:

struct vec_t {
  int *items;
  size_t size;
  size_t capacity;
};

struct vec_t *vec_alloc(void)
{
  struct vec_t *vec = malloc(sizeof(struct vec_t));

  vec->items = NULL;
  vec->size = 0;
  vec->capacity = 0;

  return vec;
}

void vec_free(struct vec_t *vec)
{
  free(vec->items);
  free(vec);
}

void vec_push(struct vec_t *vec, int item)
{
  if (vec->size == vec->capacity)
  {
    size_t new_capacity = vec->capacity > 0 ? (vec->capacity + 1) * 2 : 5;
    vec->items = realloc(vec->items, new_capacity * sizeof(int));
  }
  vec->items[vec->size++] = item;
}

现在让我们假设我们不使用_alloc()or_free()而是决定在堆栈上分配这个结构。

然后我们通过栈分配的struct( my_vec.items)间接在堆上分配数据

void main()
{
  vec_t my_vec;
  vec_push(&my_vec, 8); // allocates memory

  // vec_destroy(&my_vec); // PROBLEM

  return 0;
}

现在我们有一个问题:我们不想释放my_vec堆栈上的结构(),但我们需要释放堆(my_vec.items)上的结构分配的数据。

我相信这要么是设计问题,要么是约定问题,或者两者兼而有之。

我已经看到人们添加了一些额外的功能_init()_deinit()除了_alloc()and之外_free()

void vec_init(struct vec_t *vec)
{
  vec->items = NULL;
  vec->size = 0;
  vec->capacity = 0;
}

void vec_deinit(struct vec_t *vec)
{
  free(vec->items);
}

释放结构分配的内存是否有意义_deinit()

如果这种方法是正确的,我是否正确地说像这样分配在堆栈上的结构总是需要是_init()and _deinit()

标签: cmemorymemory-management

解决方案


如果您使用_initand_deinit函数,是的,您想要_deinit释放内存,是的,vec_init并且vec_deinit对于堆栈分配的结构是强制性的。对于这个用例,可以初始化堆栈分配的结构避免vec_t my_vec = {0};调用vec_init,但假设归零现在和永远产生一个有效初始化的结构(如果您vec_init稍后更改以使某些字段非零,则您的库的用户没有' t 使用vec_init必须更新),并且当不可避免vec_deinit的未与相应的vec_init.

请注意,代码不需要如此大量地重复;_alloc_free可以用 和 来实现_init_deinit将代码重复保持在最低限度:

struct vec_t *vec_alloc(void)
{
  struct vec_t *vec = malloc(sizeof(struct vec_t));
  if (vec) vec_init(vec);  // Don't try to init if malloc failed
  return vec;
}

void vec_free(struct vec_t *vec)
{
  if (vec) vec_deinit(vec); // Don't try to deinit when passed NULL
  free(vec);
}

推荐阅读