我是一名学习C的小伙子,我一直试图加强Simple Object System。
我有一个看起来像这样的结构:
struct Room
{
Object proto;
Monster* bad_guy;
struct Room *north;
struct Room *south;
struct Room *east;
struct Room *west;
};
我想释放这个:
void Room_destroy(void* self)
{
Room* room=self;
if(room->bad_guy)
room->bad_guy->proto.destroy(room->bad_guy);
if(room->north)
room->north.proto.destroy(room->north);//same as Room_destroy
if(room->south)
room->north.proto.destroy(room->south);////same as Room_destroy
if(room->west)
room->north.proto.destroy(room->west);////same as Room_destroy
if(room->east)
room->north.proto.destroy(room->east);////same as Room_destroy
free(room->proto.description);
free(room);
}
假设有两个房间,Room* x
和房间* y,以便x north
y
x
调用y
上的方法将调用x
上的方法{1}}会在y
上调用它,它会在StackOverflow
上调用它,这来回导致死锁。我该如何解决这个问题?
如何释放此类内存以确保不会发生内存泄漏?
我尝试实现一组函数来调用它,我得到了Segmentation fault
和 ==6446== Stack overflow in thread 1: can't grow stack to 0xffe801ff8
==6446==
==6446== Process terminating with default action of signal 11 (SIGSEGV)
==6446== Access not within mapped region at address 0xFFE801FF8
==6446== at 0x400863: Room_destroy (ex19.c:55)
==6446== If you believe this happened as a result of a stack
==6446== overflow in your program's main thread (unlikely but
==6446== possible), you can try to increase the size of the
==6446== main thread stack using the --main-stacksize= flag.
==6446== The main thread stack size used in this run was 8388608.
==6446== Stack overflow in thread 1: can't grow stack to 0xffe801fe8
==6446==
==6446== Process terminating with default action of signal 11 (SIGSEGV)
==6446== Access not within mapped region at address 0xFFE801FE8
==6446== at 0x4A256A0: _vgnU_freeres (vg_preloaded.c:58)
==6446== If you believe this happened as a result of a stack
==6446== overflow in your program's main thread (unlikely but
==6446== possible), you can try to increase the size of the
==6446== main thread stack using the --main-stacksize= flag.
==6446== The main thread stack size used in this run was 8388608.
==6446==
==6446== HEAP SUMMARY:
==6446== in use at exit: 605 bytes in 12 blocks
==6446== total heap usage: 12 allocs, 0 frees, 605 bytes allocated
==6446==
==6446== LEAK SUMMARY:
==6446== definitely lost: 0 bytes in 0 blocks
==6446== indirectly lost: 0 bytes in 0 blocks
==6446== possibly lost: 0 bytes in 0 blocks
==6446== still reachable: 605 bytes in 12 blocks
==6446== suppressed: 0 bytes in 0 blocks
==6446== Reachable blocks (those to which a pointer was found) are not shown.
==6446== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==6446==
==6446== For counts of detected and suppressed errors, rerun with: -v
==6446== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Segmentation fault
:
void Room_destroy(void* self)
这是我的代码:
if(room->north && !avoid(caller,room->north))
room->north->proto.destroy(room->north);
else
caller=room->north;
if(room->south &&!avoid(caller,room->south))
room->south->proto.destroy(room->south);
else
caller=room->south;
if(room->west && !avoid(caller,room->west))
room->west->proto.destroy(room->west);
else
caller=room->west;
if(room->east && !avoid(caller,room->east))
room->east->proto.destroy(room->east);
else
caller=room->east;
free(room->proto.description);
//room->proto=NULL;
free(room);
{ 房间*房间=自己; 如果(间 - > bad_guy) 间 - > bad_guy-> proto.destroy(间 - > bad_guy);
int avoid(Room* caller,Room* room)
{
if(caller!=room)
return 0;
return 1;
}
}
方法避免在这里:
struct Map
{
Object proto;
Room *start;
Room* location;
};
然后有一个Map结构,如下所示:
void Map_destroy(void* self)
{
Map *map=self;
if(map->start)
{
caller=map->start;
map->start->proto.destroy(map->start);
}
if(map->location)
{
caller=map->location;
map->location->proto.destroy(map->location);
}
}
在这个结构上我调用了这样的destroy方法:
case -1:
printf("Giving up? You suck\n");
if(game)
game->proto.destroy(game);
return 0;
当用户中止这样的程序时调用它:
{{1}}
答案 0 :(得分:0)
在某些时候,您可以使用方法addRoom
将您的房间添加到您的房间网络中。然后你应该有一个方法removeRoom
,它会做出相反的行动。
所以如果你的房子\建筑\房间图形处于S0状态,那么
S0-(add room x)-> S1 -(remove room x)-> S2.
S0
必须等于S2
。所以你可以使用
removeRoom(network, x)
freeRoom(x);
要一次删除所有内容,请使用
while(isEmpty(network) ){
x = getHead(network)
removeRoom(network, x)
freeRoom(x);
}
它与C
中的链表相同答案 1 :(得分:0)
您描述的情况是在具有自动垃圾收集的框架中处理得非常好的情况。如果您不希望使用这样的框架,可以使用C ++中的某些智能指针类型合理地处理它。如果要使用标准C,则需要某种方法来确定对象的最后一次引用何时消失。可以使用两种通用方法:
计算每个对象的引用数量;对任何创建持久引用或临时引用的操作的递增计数,当最后一个持久引用消失时,该引用可能是活动的,并且减少对创建导致计数递增的任何引用的销毁的计数。当计数器达到零时,删除该对象。
维护垃圾收集的对象世界,以及所有对象的外部引用列表。定期扫描外部世界引用列表并标记由外部世界引用直接引用的每个对象,或间接地通过可从外部世界引用访问的对象。任何数量的外部世界引用都可能指向GC Universe中的任何对象,但每个外部世界引用对象都应具有明确的所有者和生命周期。
我不知道我已经看过C代码来争夺一个通用的GC世界,尽管多年来已经为各种机器实现了许多专门的垃圾收集器。
答案 2 :(得分:0)
使用引用计数: 北部和东部的Std :: shared_ptr,南部和西部的std :: weak_ptr。
共享ptr计算对象的引用数,并在销毁最后一个引用时将其删除。弱指针允许您访问共享ptr指向的对象,但不添加到引用。你需要weak_ptr来打破这里的循环引用。
答案 3 :(得分:0)
对于较长的房间链,使用avoid(caller, …)
的方法无法工作(即使对两个相邻房间正确实施);考虑e。克。
P---Q
| |
R---S
- 如果我们从破坏房间S开始,我们可以到达房间Q,从那里到房间P,然后到房间R然后回到S,在那里我们需要回忆起第四个房间,以便检测到我们来自这里,而不是再次跑来跑去,但我们不能只召回第四个房间。
另一方面,我们不需要垃圾收集或引用计数;它将为一个被破坏的房间进行标记,而不是重新访问一个标记的房间。那么,什么用于商标?您可以将另一个成员添加到struct Room
,或者,如果room->proto.description
始终为非NULL,则将其用作标记标记,例如:克。
void Room_destroy(void *self)
{
Room *room = self;
if (!room->proto.description) return; // been here
free(room->proto.description),
room->proto.description = NULL; // mark as visited
if (room->bad_guy) room->bad_guy->proto.destroy(room->bad_guy);
if (room->north) room->proto.destroy(room->north); //same as Room_destroy
if (room->south) room->proto.destroy(room->south); //same as Room_destroy
if (room->west) room->proto.destroy(room->west); //same as Room_destroy
if (room->east) room->proto.destroy(room->east); //same as Room_destroy
free(room);
}