In what context does the delete operator throw an error?
Asked Answered
S

2

6

In my implementation of a linked-list, my helper function deleteNode(Node*) that deletes inner class Node instances is throwing a runtime error, by "triggering a breakpoint" in the Local Windows Debugger in VS 2015. I am being careful to match my new and delete operators. Does scope/reference play a role that I don't realize?

Even if there is a logic error in clear() and deleteNode() gets passed nullptr, it shouldn't throw an error to delete nullptr, and then assign nullptr to itself right? What is the issue with that delete?

class LinkedList {
public:
    LinkedList() : head(nullptr) {}
    ~LinkedList() { clear(); }

    void push_front() {
        head = createNode(head);
    }

    void clear() {
        Node* current_node = head;
        while (current_node != nullptr) {
            Node* next_node = current_node->next; // buffer
            deleteNode(current_node);
            current_node = next_node;
        }
    }

private:    
    struct Node {
        Node(Node* next)
            : next(next) {}
        Node* next;
    };
    Node* head;
    Node* createNode(Node* next) {
        return new Node(next);
    }
    void deleteNode(Node*& toDelete) {
        delete toDelete; // ***VS 2015 puts breakpoint here***
        toDelete = nullptr;
    }
};

int main() {
    auto A = LinkedList();
    A.push_front();
    A.clear();
    return 0;
}

I have removed all attributes and methods not relevant to the error. This dummy code still throws the same error.

Scopas answered 23/2, 2016 at 7:28 Comment(3)
Rule of Five: You need custom copy and move operations.Shend
@Shend I'm unfamiliar with what you are referring to. Could you link me to a resource explaining it or elaborate on that yourself?Scopas
I think it's not related to your problem, but will cause issues in the future if you're not paying attention to it. The phrase "rule of Five", or formerly "rule of three", will lead you to many articles such as en.cppreference.com/w/cpp/language/rule_of_threeShend
N
6

The problem lies within your clear() function. You see, you think that because of the way you've written your deleteNode function, all your nodes will be nullptr after clear. That is unfortunately not true. You copy your head into current_node, and the copy of head (i.e. current_node) turns into nullptr when it gets deleted, but head remains non-null. Later the destructor attempts to delete it again. Calling delete on already freed memory results in Undefined Behavior.

To fix, add

 head = nullptr;

in the end of your clear function

Noleta answered 23/2, 2016 at 7:44 Comment(1)
Thank you. Just to clarify, even though I pass the pointer by reference to deleteNode, since current_node is only a copy of head, head does not get set to nullptr. Right?Scopas
L
4

In what context does the delete operator throw an error?

A delete expression can throw, if the destructor itself throws, or a destructor of a sub object. But you should avoid throwing in a destructor.

A delete expression might also have undefined behaviour if you try to delete a pointer that does not point to a valid object. An exception is nullptr, which is safe to delete. Typical causes for accidentally deleting an invalid pointer is trying to delete same pointer value twice, or forgetting to initialize memory. Undefined behviour can result in anything, including an error being thrown.

What is the issue with that delete?

You're deleting the same pointer twice. You can verify that by checking the value in a debugger.

Luby answered 23/2, 2016 at 7:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.