【问题标题】:calling free on struct throws runtime error在 struct 上调用 free 会引发运行时错误
【发布时间】:2013-12-13 08:28:18
【问题描述】:

我已经创建了一个基于Simple Object System 的简单对象系统。然后我决定通过添加一个函数来扩充代码,以便在怪物死亡时释放所有关于怪物的内存:

void Monster_destroy(void *self)
{
    Monster* monster=self;
    if(&(monster->proto))
        free(&(monster->proto));
    free(monster);
}

我在这里使用的函数是这样的:

int Monster_attack(void* self,int damage)
{
    Monster* monster=self;
    char* desc=monster->proto.description;
    printf("You attack %s!\n", desc);
    monster->hit_points-=damage;
    if(monster->hit_points>0)
    {
        printf("It is still alive\n");
        return 0;
    }
    else
    {
        printf("It is dead\n");
        monster->proto.destroy(monster);
        return 1;
    }       
}

我收到以下错误:

==4699== Invalid free() / delete / delete[] / realloc()
==4699==    at 0x4C2B83A: free (vg_replace_malloc.c:468)
==4699==    by 0x40080F: Monster_destroy (ex19.c:15)
==4699==    by 0x400A2C: Room_attack (ex19.c:96)
==4699==    by 0x400ACA: Map_attack (ex19.c:118)
==4699==    by 0x400E20: process_input (ex19.c:175)
==4699==    by 0x400F52: main (ex19.c:211)
==4699==  Address 0x51fd500 is 0 bytes inside a block of size 56 free'd
==4699==    at 0x4C2B83A: free (vg_replace_malloc.c:468)
==4699==    by 0x400803: Monster_destroy (ex19.c:14)
==4699==    by 0x400A2C: Room_attack (ex19.c:96)
==4699==    by 0x400ACA: Map_attack (ex19.c:118)
==4699==    by 0x400E20: process_input (ex19.c:175)
==4699==    by 0x400F52: main (ex19.c:211)
==4699== 

我有一个怪物看起来像这样的系统:

struct Monster
{
    Object proto;
    int hit_points;
};

typedef struct Monster Monster;

Object 是一个看起来像这样的结构:

typedef struct
{
    char *description;
    int (*init)(void *self);
    void (*describe)(void* self);
    void (*destroy)(void* self);
    void* (*move)(void* self,Direction direction);
    int (*attack)(void* self,int damage);
}Object;

这就是我现在使用 `Monster_destroy 的方式:

 if(monster && monster->hit_points>0)
{
    monster->proto.attack(monster,damage);
    return 1;
}
else
{
           //dont even call Monster_attack because Monster has no hit_points
    printf("You flail at the air and hit nothing,Idiot\n");
    if(monster)
    monster->proto.destroy(monster);
    return 0;
}

【问题讨论】:

  • 我觉得最后这个free(monster)没什么用,因为它只是栈上的一个指针(你没有在堆上分配)。
  • 虽然关于您发布的代码的答案听起来是正确的,但我想指出一个事实,即 Valgrind 显示的调用堆栈与 Monster_attack 无关,尽管有 @987654330 @。你确定你有正确的功能吗?
  • 哦,等等,我将 Monster_destroy 的调用从 Monster_attack 更改为 Room_attack,因为我想看看它是否在那里工作。

标签: c struct function-pointers free


【解决方案1】:

在您的 struct Monster proto 中是 Object 而不是 Object *

所以在Monster_destroy()函数中这样释放内存是无效的。

if(&(monster->proto))
    free(&(monster->proto));

事实上,你并没有专门为proto分配内存,所以你不需要释放它。

但是,如果为proto->description 分配了内存,则需要使用free(proto->description) 释放它。

【讨论】:

  • 如何在释放description 后将proto 设置为NULL,如上所述,它给了我incompatible types when assigning to type ‘Object’ from type ‘void *’
【解决方案2】:

当您声明变量时,它们会从系统堆栈中获取内存。但是当您声明指针并为其分配内存时,它会从堆中分配。这就是为什么您可以使用从堆中分配的free()(动态)释放内存的原因。但是您不能尝试使用 free 删除堆栈中分配的内存。

【讨论】:

    【解决方案3】:

    我觉得应该简单写成这样:

    void Monster_destroy(void *self)
    {
      Monster* monster = self;
      if(&(monster->proto) != NULL)
        free(&(monster->proto));
    
      monster->proto = NULL;//Important
    }
    

    你对怪物变量所做的最后一次释放是无用的(充其量),因为你传递了一个位于堆栈中的地址(当函数返回该地址时,通过将 sp 寄存器移回自动删除该地址)。

    您应该只在动态分配的内存上使用 free,例如您使用“malloc”或“new”创建的内存。

    【讨论】:

    • 由于proto 不是动态分配的,您不能在其上使用free()。所以你的代码是错误的。
    【解决方案4】:

    struct Monster 中,proto 不是动态分配的,因此您不必释放它。

    尝试不使用线条:

    if(&(monster->proto))
        free(&(monster->proto));
    

    在函数Monster_destroy中。

    记住,只有在指针上使用过malloc() 时,才在指针上使用free()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-31
      • 2021-05-29
      • 2016-12-03
      • 2014-03-07
      • 2015-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多