【问题标题】:C++ destructor exampleC++ 析构函数示例
【发布时间】:2011-01-11 09:47:42
【问题描述】:

我的 C++ 有点生疏了,但我制作了一个反转链表的程序,现在我正在尝试为它编写适当的析构函数,但我不知道到底要销毁什么。这是我的类定义:

class LinkedList
{
    private:ListElement *start;
    public:LinkedList();
    public:void AddElement(int val);
    public:void PrintList();
    public:void InvertList();
};

class ListElement
{
    public:int value;
    public:ListElement * link;
    public:ListElement(int val);
    public:ListElement();
};


class Stack
{

private:ListElement ** stack;
private:int index;
public:Stack(int size);
public:void push(ListElement * le);
public:ListElement * pop();

};

堆栈用于我反转列表时。 反正 ... 我将如何为这些编写析构函数? 我在想:

对于 ListElement,将值设为 0,将链接设为 0(NULL)。

对于 LinkedList,遍历元素并为所有元素调用 ListElementDestructor。

我对此不太确定,因为据我所知,析构函数会自动调用成员对象的析构函数,所以在这种情况下,只为 LinkedList 编写一个空的析构函数就足够了吗?我不知道...这就是我问的原因

对于我不知道的堆栈......在列表反转后指针已经为0(NULL),因为它们都被弹出了。

我有点困惑。 任何人都可以帮忙吗? 提前谢谢你。

【问题讨论】:

  • 在元素之间交换指针的方向而不是使用堆栈不是更容易吗?
  • 不需要重复 private 和 public 关键字。只做私有://私有 var 声明 public://公共 var 声明
  • 我还建议将 listElement 的“链接”成员设为私有,并通过 next() 方法提供对其的只读访问权限

标签: c++ linked-list destructor


【解决方案1】:

你破坏了需要破坏的东西。如果您的类使用 new 创建对象,您可能需要使用析构函数删除它们的析构函数。请注意,像 LinkedList 这样的容器应该只包含已动态分配或未动态分配的元素。如果您将两者混合,或者混合原件和副本,我怀疑您正在这样做,您可能需要使用智能指针或引用计数。

其次,如果您确实需要反转单链表(在 30 年的编程中我从未需要这样做),您只是使用了错误的数据结构 - 您应该使用双向链表,在这种情况下,不需要做任何事情。

第三,我可以说你的 C++ 风格是非惯用的,对我来说几乎不可读 - 让 C++ 看起来像 Java 不是一个好主意。改为:

class LinkedList
{
    private:
       ListElement *start;
    public:
       LinkedList();
       void AddElement(int val);
       void PrintList();
       void InvertList();
};

【讨论】:

  • 嗯...实际上我曾经在一次求职面试中遇到过这个问题:“编写适当的代码(包括类结构)以反转单个链表”。我强调“单链表”。我在 Pascal 的高中和 Java 的大学也这样做过。抱歉让 C++ 看起来像 Java,我真的不是故意的,我想我只是习惯了这样写东西。
【解决方案2】:

对于 ListElement,将值设为 0,将链接设为 0(NULL)。

您不需要重置析构函数中的任何值,因为在析构函数执行后值将不存在。

您需要确定的主要事情是,在堆上分配的所有元素(即使用new)都使用delete(或delete [],在数组的情况下)删除。

对于 LinkedList,遍历元素并为所有元素调用 ListElementDestructor。

对于分配在堆栈上的对象,当对象超出范围时会自动调用它。
对于动态分配的对象(即使用new 创建的),当调用析构函数时 使用delete 将其删除。换句话说,您不需要调用任何析构函数,因为如果您正确清理对象,它们会自动调用。

假设(我假设)您在 LinkedList 类的堆上分配新的 ListElement,您应该确保在 LinkedList 析构函数中,通过遍历列表并在每个 ListElement 上调用 delete(当然,在您从中检索下一个列表元素的地址之后)。像这样的:

ListElement* current = list.start;    
while( current ){
    ListElement* next = current->next;
    delete current;
    current = next;
}

ListElement 类中没有什么需要清理的,因为虽然它有一个指向下一个元素的指针,但删除可能应该在 LinkedList 类中处理,这意味着它不需要析构函数。
不需要为每个类编写析构函数,因为编译器会自动为您生成一个空的。

正如我在 cmets 中所说,您不应该使用堆栈来反转链表。您应该只是交换指针的方向。
一个简单的示例,大致说明您想要的那种东西。

ListElement* previous = 0;
ListElement* current = list.start;

while( current->next ){
    //copy the address of current item on the list
    ListElement* next = current->next;

    //point the current list item to the previous list item
    current->next = previous;

    //set the current list item to the next list item
    current = next;

    //and the previous list item to the current one
    previous = current;
}
//set the start of the list to what was the end
list.start = current;

【讨论】:

  • 这是我在高中时用堆栈学会的方法。如果你能告诉我如何扭转指针,我将非常感激。我不知道这可以通过任何其他方式完成。这只是我脑海中浮现的第一件事。我愿意接受任何其他解决方案。事实上,我会很感激。
  • @Para 我在我的帖子中编辑了一些粗略(未经测试)的代码,用于通过交换指针来反转链表。即使它不能 100% 正确工作,它也应该让您知道如何去做。
【解决方案3】:

LinkedList 类创建 ListElements。所以你需要从列表的开头循环到结尾(除非它是空的。)并且:

delete currentElement;

在 LinkedList 析构函数中。由于 ListElement 将值存储为“int”,因此您实际上不需要在此处释放内存。和你想的一样。

同样,无需在 Stack 类的析构函数中释放内存。一般来说,删除你的新内容!并让一个人(班级)负责这项工作!

【讨论】:

    猜你喜欢
    • 2011-05-12
    • 2012-07-28
    • 2013-10-08
    • 2014-05-27
    • 2011-04-03
    • 2010-12-16
    • 2014-02-26
    • 2011-09-01
    • 2017-03-16
    相关资源
    最近更新 更多