如何寻找悬空指针?

How to look for dangling pointers?

提问人:Horsio 提问时间:12/2/2022 最后编辑:mchHorsio 更新时间:12/2/2022 访问量:114

问:

我正在尝试在 C++ 中为链表构建一个类。我的教授说我的代码中有一个悬空的指针。我花了几个小时寻找它,但无论如何我都找不到它。我试着问一个朋友,他们也找不到。有没有办法在代码中查找悬空指针或识别它们?我会附上我的代码,以防万一它很明显,但老实说,我不知道这个悬空的指针在哪里。我知道这段代码不是最好的,但它已经通过了我和我教授的所有测试,除了有一个悬空的指针。我也听说过一种叫做智能指针的东西,但我认为我们不应该使用它,我不知道它们是什么。任何帮助找到此指针都是值得赞赏的。

#include "IntList.h"
    #include <ostream>
    using namespace std;

    IntList::IntList() {
        head = nullptr;
        tail = nullptr;
    }

    IntList::IntList(const IntList &cpy) {
        
        if(cpy.head == nullptr) {
            head = nullptr;
            tail = nullptr;
        }
        else {
            IntNode *currNode = cpy.head;
            IntNode *temp = cpy.head;
            head = new IntNode(0);
            head->value = temp->value;
            currNode = head;
            temp = temp->next;

            while(temp != nullptr) {
                currNode->next = new IntNode(0);
                currNode = currNode->next;
                currNode->value = temp->value;
                currNode->next = nullptr;
                temp = temp->next;
            }
            tail = currNode;
        }
    }

    IntList::~IntList() {
        clear();
    }

    void IntList::push_front(int value) {
        IntNode *temp = new IntNode(value);
        if(head == nullptr) {
            head = temp;
            tail = head;
        }
        
        else {
            temp->next = head;
            head = temp;
        }
    }

    void IntList::pop_front() {
        if(empty()) {
            return;
        }
        else if(head->next == nullptr) {
            delete head;
            head = nullptr;
            tail = nullptr;
        }
        else {
            IntNode *temp = head;
            head = head->next;
            delete temp;
            temp = nullptr;
        }
    }

    void IntList::push_back(int value) {
        IntNode *temp = new IntNode(value);
        if(tail != nullptr) {
            tail->next = temp;
        }
        tail = temp;
        if(head == nullptr) {
            head = tail;
        }
    }

    bool IntList::empty() const {
        if(head == nullptr) {
            return true;
        }
        return false;
    }

    const int & IntList::front() const {
        return head->value;
    }

    const int & IntList::back() const {
        return tail->value;
    }

    void IntList::clear() {
        IntNode *currNode = head;
        IntNode *temp = currNode;
        // unsigned i = 1;
        while(currNode != nullptr) {
            currNode = currNode->next;
            temp->next = nullptr;
            delete temp;
            temp = currNode;
            // cout << "deleted node " << i << endl;
            // i++;
        }
        head = nullptr;
        tail = nullptr;
    }

    void IntList::selection_sort() {
        IntNode *loc = nullptr;
        IntNode *temp = new IntNode(0);
        IntNode *currNode = nullptr;
        IntNode *swap = nullptr;
        int min = 0;

        if(head == nullptr) {
            return;
        }
        else if(head->next == nullptr) {
            return;
        }
        else {
            for(currNode = head; currNode != nullptr; currNode = currNode->next) {
                loc = currNode;
                min = currNode->value;
                for(swap = currNode; swap != nullptr; swap = swap->next) {
                    if(swap->value < min) {
                        min = swap->value;
                        loc = swap;
                    }
                }
                temp->value = currNode->value;
                currNode->value = loc->value;
                loc->value = temp->value;
            }
        }
        
        delete temp;
        temp = nullptr;
    }

    void IntList::insert_ordered(int value) {
        if(head == nullptr || head->value >= value) {
            push_front(value);
        }
        else if(tail->value <= value) {
            push_back(value);
        }
        else {
            IntNode *newNode = new IntNode(value);
            for(IntNode *currNode = head; currNode != tail; currNode = currNode->next) {
                if(currNode->next->value > newNode->value) {
                    newNode->next = currNode->next;
                    currNode->next = newNode;
                    break;
                }
            }
        }
    }

    void IntList::remove_duplicates() {
        if(head == nullptr) {
            return;
        }
        else if(head->next == nullptr) {
            return;
        }
        else {
            IntNode *temp = head;
            for(IntNode *currNode = head; currNode != nullptr; currNode = currNode->next) {
                temp = currNode;
                for(IntNode *check = currNode->next; check != nullptr; check = check->next) {
                    if(check->value == currNode->value) {
                        temp->next = check->next;
                        if(check == tail) {
                            tail = temp;
                        }
                        if(check->next != nullptr) {
                            check->next = nullptr;
                        }
                        
                        delete check;
                        check = temp;
                    }
                    temp = check;
                }
            }
        }
    }

    IntList & IntList::operator=(const IntList &rhs) {
        IntList *newList = new IntList(rhs);
        swap(newList->head, head);
        newList->clear();
        delete newList;
        return *this;
    }

    ostream & operator<<(ostream &out, const IntList &rhs) {
        IntNode *currNode = rhs.head;
        while(currNode != nullptr) {
            out << currNode->value;
            currNode = currNode->next;
            if(currNode != nullptr) {
                out << " ";
            }
        }
        return out;
    }

    IntNode * IntList::min(IntNode *min) {
        return nullptr;
    }

    void IntList::copy(const IntList &) {}

我尝试在适当的时候删除内存,我通常会在确保它们没有悬空之后将指针分配给 nullptr。我真的不知道我做错了什么,它通过了测试,但显然在长时间使用后,它会导致不确定的行为。

C++ 空指针

评论

5赞 mch 12/2/2022
使用 编译测试。当您使用悬空指针时,它会找到它,但如果它是未使用的悬空指针,则不会。-fsanitize=address -g
0赞 john 12/2/2022
你的表情让我感到不安。它看起来像是对复制和交换习语的错误实施尝试,问题是它不更新。我想这是一个悬而未决的指针,尽管我不确定这些术语是否有帮助。operator=tail

答:

1赞 john 12/2/2022 #1

被窃听了。这是一个显示错误的测试operator=

int main()
{
    IntList x;
    x.push_back(1);
    x.push_back(2);
    IntList y;
    y.push_back(3);
    y.push_back(4);
    x = y;
    cout << x.back() << '\n';
}

这输出(对我来说)而不是预期的.该 bug 的原因是无法更新成员变量。我想你可以称之为悬空指针。-5726623074operator=tail

如果你有一个复制构造函数和一个交换成员函数,那么简单可靠的实现方法是使用复制和交换习惯用语。看起来你正在尝试,但如果是这样,那么你就犯了错误。operator=

要回答所提出的问题,不,没有万无一失的方法来识别悬空指针。首先尽量不要使用它们(即指针)是最好的建议。但是,当你学习时,你显然必须经历痛苦。