链表析构函数C ++

时间:2017-10-15 18:52:15

标签: c++ constructor linked-list aggregate destructor

我正在学习使用链表实现Stack。这是节点类:

class StudentInfo {
    public:
        string id, name, course;
        double GPA;
        StudentInfo *next;
};

这是Stack类:

class StackLinkedList {
    public:
        StudentInfo* top; //pointer to point to the top node
        int size; //variable to keep the size of the stack

    //constructor
    StackLinkedList() {
        this->size = 0;
        this->top = NULL;
    }

    //destructor
    ~StackLinkedList() {
        StudentInfo *current = top;
        while (top) {
            current = current->next;
            delete top;
            top = current;
        }
    }

    //to add item into stack - push on top
    void push(StudentInfo *newStudent) {
        if (!top) {
            top = newStudent;
            return;
        }

        newStudent->next = top;
        top = newStudent;
        size++;
    }

void main() {
    StudentInfo s1("phi", "123", "computer science", 4.0);
    StudentInfo s2("abc", "123", "software engineer", 4.0);
    StudentInfo s3("zxc", "123", "business management", 4.0);

    StackLinkedList list;
    StudentInfo *ptr;
    ptr = &s1;
    list.push(ptr);
    ptr = &s2;
    list.push(ptr);
    ptr = &s3;
    list.push(ptr);

};

当我尝试在push()和printAll()上运行单元测试时,一切正常。但是,在调用了析构函数()之后,出现错误Debug Assertion Failed ... is_block_type_valid(header-> _block_use)。并且调试器在delete top;

处触发了断点
//destructor
~StackLinkedList() {
    StudentInfo *current = top;
    while (top) {
        current = current->next;
        delete top; //here
        top = current;
    }
}

如果我将top = NULL;放在delete top;之前,则错误消失了。所以,我对top = NULL;语句有点混淆。 编辑:NodeType的构造函数

 StudentInfo(string id, string name, string course, double gpa) {
        this->id = id; this->name = name; this->course = course; this->GPA = gpa; this->next = NULL;
}

2 个答案:

答案 0 :(得分:4)

您通过尝试自动存储时间delete个对象来调用未定义的行为。

int main() {
    StudentInfo s1("phi", "123", "computer science", 4.0);
    StudentInfo s2("abc", "123", "software engineer", 4.0);
    StudentInfo s3("zxc", "123", "business management", 4.0);

    StackLinkedList list;
    StudentInfo *ptr;
    ptr = &s1;
    list.push(ptr);
    ptr = &s2;
    list.push(ptr);
    ptr = &s3;
    list.push(ptr);

};

如您所见,s1s2s3自动存储持续时间的对象(也就是说,编译器会在最后自动调用它们的析构函数他们的一生)。

然而,你将它们的地址传递给list,其破坏者deletes在其链接列表详细信息中的所有指针都会被破坏....永远不要在指针上调用delete使用new创建的对象。

一些补充说明:

  • void main()在C ++中是非法的。你使用的是较旧的编译器吗? ..
  • 每个对象都应该管理其资源。例如,std::forward_list使用分配器在内部管理其节点的分配。我建议你重新设计StackLinkedList以在内部管理它的节点,这样客户就永远不会为生命而烦恼。
  • 您应该阅读Rule of ThreeThe Rule of Five
  • 您的代码中还有其他一些错误,我没有碰过。

答案 1 :(得分:1)

对于初学者,您不会初始化next类型对象的数据成员StudentInfo

因此依赖于列表中最后一个节点等于nullptr的所有代码都将调用未定义的行为。

此外,您不能对不是使用operator new创建的对象使用operator delete。

所以代替陈述

StudentInfo s1("phi", "123", "computer science", 4.0);
StudentInfo s2("abc", "123", "software engineer", 4.0);
StudentInfo s3("zxc", "123", "business management", 4.0);

你至少应该写(我假设StudentInfo是一个聚合。如果该类有一个构造函数,那么声明它就像

StudentInfo( const string &id, 
             const string &name, 
             const string &course, 
             double gpa, 
             StudentInfo *next = nullptr ) 
{
        this->id = id; this->name = name; this->course = course; this->GPA = gpa; this->next = next;
}

)     StudentInfo * s1 =新的StudentInfo {" phi"," 123","计算机科学",4.0,nullptr};     StudentInfo * s2 =新的StudentInfo {" abc"," 123","软件工程师",4.0,nullptr};     StudentInfo * s3 =新的StudentInfo {" zxc"," 123","业务管理",4.0,nullptr};

然后

list.push(s1);
list.push(s2);
list.push(s3);