1

我写了一个双向链表(在这种情况下存储素数),在使用列表后我试图删除其中的元素。我在列表的析构函数中编写了一个简单的循环。但是,我可以在删除每个元素后打印每个元素中保存的值。释放内存后,我预计会出现“错误访问”错误。此外,我使用 Activity Monitor 来显示在程序执行的各个点上使用的资源。创建链表时(显然)内存使用量大幅增加,但在调用析构函数后也有小幅增加。我认为有什么地方不对劲。

正在为列表的每个成员调用“删除”语句,但它似乎没有做任何事情。我在下面的析构函数中包含了相关代码。列表和元素是使用“new”语句创建的。“当前”、“头”和“尾”标签是指向列表元素(节点)的指针。

PrimeList::~PrimeList()
{
    // delete list elements
    do
    {
        current = tail;
        tail = tail->previous;
        delete current;
    }
    while( tail != NULL );

    // nullify the pointers
    head = NULL;
    tail = NULL;
    current = NULL;

    // reset size
    size = 0;
}

有什么见解吗?

4

5 回答 5

2

删除一个对象不一定会改变该对象曾经占用的内存,更不用说使该内存不可用于后续访问。有多种方法可以确保您的程序不会访问已删除的内存,例如使用调试分配器以不寻常的位模式覆盖已删除的内存,或使用动态分析工具(如valgrind)。

于 2012-08-26T23:55:11.307 回答
1

您是否通过引用将列表的头部传递给删除方法?

否则,您只是在尝试删除列表的副本,因此当您尝试访问它时列表仍然存在。

我看不到你的整个代码,但是对于析构函数,你应该这样做:

PrimeList::~PrimeList()
{
  deleteList( &head); // pass the reference to the head pointer
}

void PrimeList::deleteList( struct node** headRef)
{
  struct node* head = *headRef;
  // now apply your deletion algorithm
}
于 2012-08-26T23:55:03.180 回答
1

delete所做的只是使对象使用的内存可供另一个对象重用(并调用析构函数,如果有的话)。它不会擦除内存或将其标记为不可用或其他任何内容(至少,它不能保证 - 如果感觉如此,它可能会)。在将来的某个时间,该内存可能会分配给另一个对象,届时它将被覆盖。

deleted 内存不会归还给系统,它由您的进程保留,以供将来new的 s(和malloc,...)重用。这就是为什么活动监视器仍然认为您正在使用该内存的原因。有更好的方法可以确定您是否已正确释放列表,搜索“c++ 内存泄漏检测器”或类似的方法。

于 2012-08-26T23:55:35.100 回答
1

很可能是您的编译器在“帮助您”。在链表中实现析构函数的一个好方法是递归。假设您的列表中的每个条目都有一个类节点,

class Node {
    public:
    ~Node() {delete this->next;}
};

PrimeList::~PrimeList() {
    delete head;
}
于 2012-08-26T23:56:43.903 回答
1

在删除元素后访问它是一个错误。当然,其中包含错误的代码不会像您期望的那样工作。这就是我们试图避免此类代码的原因。

你的析构函数看起来不错。最有可能的是,您的析构函数在内部只是使内存可供重用。由于您没有更改其内容或分配任何新对象,因此它仍然“碰巧拥有”相同的内容。

于 2012-08-26T23:50:14.963 回答