有没有办法在销毁链表时取消引用 nullptr 时停止接收异常错误?

Posted

技术标签:

【中文标题】有没有办法在销毁链表时取消引用 nullptr 时停止接收异常错误?【英文标题】:Is there a way to stop receiving an exception error when dereferencing a nullptr while destroying a linked list? 【发布时间】:2021-02-12 16:32:46 【问题描述】:

我需要销毁一个数组(通过散列填充和访问),其中多个指针指向 nullptr。我从教科书中复制了用于销毁链表的确切示例,但是当我尝试释放用于 Node 对象的内存时,仍然出现运行时异常。

我是否可以简单地告诉 Visual Studios 在执行期间忽略 nullptr 取消引用异常,或者是否有适当的方法来解除分配书中未显示的此类链表? enter image description here

#pragma once
#include <iostream>
#include <string>
#include <array>
#include <fstream>

class Manager 
    struct Node 
        int ID, type, capacity, DOB;
        std::string Name;
        Node* next = 0;

        Node(int ID, int type, std::string Name, int DOB, int capacity) :
            ID(ID),
            type(type),
            Name(Name),
            DOB(DOB),
            capacity(capacity)
        
    ;

    std::array<Node*, 10> head;

    public:
        Manager();
        int h(int);
        void add(int, int, std::string, int, int);
        void print(int);
        void printAll();
        void deleteOne(int);
        ~Manager();
;
#include "Manager.h"
Manager::Manager() 
    head.fill(0);
    std::fstream records;
    records.open("shipRecords.txt", std::ios::in);
    if (records.is_open()) 
        while (!records.eof()) 
            int ID, type, DOB, capacity;
            std::string Name;
            records >> ID >> type >> Name >> capacity >> DOB;
            add(ID, type, Name, capacity, DOB);
        
        std::cout << "RECORDS INITIALIZED" << std::endl;
    
    else 
        std::cout << "FILE NOT OPEN" << std::endl;
    


Manager::~Manager() 
    for (int i = 0; i < head.size(); i++) 
        Node* ptr = head[i];
        Node* next = ptr;
        while (ptr) 
            next = ptr->next;
            delete ptr;
            ptr = next->next;
        
    

在以下函数中取消引用 nullptrs 时,我没有遇到同样的问题。

void Manager::print(int ID) 
    Node* ptr = head[h(ID)];
    if (ptr) 
        while (ptr->ID != ID && ptr)
            ptr = ptr->next;

        if (!ptr)
            std::cout << "SHIP DOES NOT EXIST" << std::endl;

        std::cout << ptr->ID
            << " " << ptr->type
            << " " << ptr->Name
            << " " << ptr->DOB
            << " " << ptr->capacity
            << std::endl;
    
    else 
        std::cout << "SHIP DOES NOT EXIST" << std::endl;
    


void Manager::printAll() 
    int items = 0;
    for (int i = 0; i < head.size(); i++) 
        Node* ptr = head[i];
        while (ptr) 
            items++;
            std::cout << ptr->ID
                << " " << ptr->type
                << " " << ptr->Name
                << " " << ptr->DOB
                << " " << ptr->capacity
                << std::endl;
            ptr = ptr->next;
        

        if (items == 0 && i == head.size() - 1)
            std::cout << "NO SHIPS IN THE LIST" << std::endl;
    

【问题讨论】:

不要取消引用空指针。这不是销毁链表以取消引用任何内容的必要步骤。 Manager 是链表吗?我不得不问的事实指向糟糕的设计。您是要制作链表还是数组列表? print函数中,在if (!ptr) std::cout &lt;&lt; "SHIP DOES NOT EXIST" &lt;&lt; std::endl;之后应该退出函数。 @sweenish 对于赋值,我们应该创建一个指向节点(Ship 对象)的指针数组。我们使用散列函数 ID%10 填充这个数组。它应该教我们碰撞和链接。 那么听起来你根本不像在使用链表。 “多个指针指向 nullptr” - 我认为您的意思是“多个指针为空”。 (您写的内容意味着您有一个指向std::nullptr_t 的指针,如std::nullptr_t * ptr,并且指向的东西 *ptrnullptr。我写的内容将描述一个指针,例如Node* ptr,它本身被分配了一个空指针值,例如nullptr。) 【参考方案1】:

有没有办法在销毁链表时取消引用 nullptr 时停止接收异常错误?

不,取消引用 nullptr 会使您的程序具有未定义的行为。更正您的代码,使其永远不会尝试取消引用 nullptrs。

【讨论】:

【参考方案2】:

你的问题就在这里:

while (ptr) 
    next = ptr->next;
    delete ptr;
    ptr = next->next;

您的意思是,如果我知道ptr 是有效的,那么将它指向的任何内容作为其next 并将其存储在变量next 中(imo 不是一个好名字)。然后释放ptr。最后,分配ptrnext 指向的指针。

但是你不能保证next 是一个好的(非空)指针!

这看起来像是一个错字,应该是:

while (ptr) 
    next = ptr->next;
    delete ptr;
    ptr = next;

【讨论】:

【参考方案3】:

这个方法看起来很可疑:

Manager::~Manager() 
    for (int i = 0; i < head.size(); i++) 
        Node* ptr = head[i];
        Node* next = ptr;
        while (ptr) 
            next = ptr->next;
            delete ptr;
            ptr = next->next;
        
    

您将 next 设置为 ptr-&gt;next。没关系。您正在删除 ptr,您已经对其进行了空检查。

但是你设置了ptr = next-&gt;next。而且您真的只想将其设置为next。我敢打赌这就是你的错误所在。

【讨论】:

以上是关于有没有办法在销毁链表时取消引用 nullptr 时停止接收异常错误?的主要内容,如果未能解决你的问题,请参考以下文章

关于在链表中使用时取消引用指针

Rails - 在before_destroy回调时取消销毁

C++/CLI 引用未在后续进入本地块时初始化为 nullptr

有没有办法访问/取消引用并查找存储在双指针向量中的元素的值? [关闭]

有没有办法限制在 spark sql 中加入表时读取的数据?

试图了解如何在迭代反转链表时修改列表