简体   繁体   中英

C++11 Correct usage of smart pointers in a doubly linked list

I am trying to use some new design techniques to implement a linked list,

but I can't seem to figure out just the right way to do it .

The techniques are smart pointers and the null object pattern .

The problems I'm having are with the destruction of the entire list ,

I had one implementation where it did not destruct a few objects,

now I seem to have a cyclic problem and it does not exit at all.

Follows the code:

linkedlist.h

    #pragma once
    #include <memory>
    #include "node.h"

    class LinkedList {
    public:
        LinkedList() : m_size(0), head(nullptr) {};
        void addNode(int value);
        void removeNode(int index);
    private:
        std::shared_ptr<Node> getNodeAtIndex(int index);
        std::shared_ptr<Node> getLastNode();
        void _addNode(int value);
        inline void increaseSize() { ++m_size; }
        inline void decreaseSize() { --m_size; }
    private:
        size_t m_size;
        std::shared_ptr<Node> head;
    };

linkedlist.cpp

    #include "linkedlist.h"

    void LinkedList::addNode(int value) {
        _addNode(value);
        increaseSize();
    }

    void LinkedList::_addNode(int value) {
        if (nullptr == head) {
            head = std::make_shared<Node>(Node(value));
            return;
        }
        std::shared_ptr<Node> tail = getLastNode();
        std::shared_ptr<Node> nextNode = std::make_shared<Node>(Node(value));
        nextNode->setPrevious(tail);
        tail->setNext(nextNode);
    }

    void LinkedList::removeNode(int index) {
        std::shared_ptr<Node> node = getNodeAtIndex(index);
        node->getNext()->setPrevious(node->getPrevious());
        node->getPrevious()->setNext(node->getNext());
        decreaseSize();
    }

    std::shared_ptr<Node> LinkedList::getNodeAtIndex(int index) {
        std::shared_ptr<Node> node = head;
        for (int i = 0; i < index; ++i) {
            node = node->getNext();
        }
        return node;
    }

    std::shared_ptr<Node> LinkedList::getLastNode() {
        return getNodeAtIndex(m_size-1);
    }

Node.h

    #pragma once
    #include <memory>

    class Node {
    public:
        Node() : value(0), next(nullptr), previous(nullptr) {};
        Node(int value) : value(value) {};
        ~Node() { printf("%d", value); };
        std::shared_ptr<Node> getNext();
        virtual void setNext(std::shared_ptr<Node> newNext);
        std::shared_ptr<Node> getPrevious();
        virtual void setPrevious(std::shared_ptr<Node> newPrevious);
    private:
        int value;
        std::shared_ptr<Node> next;
        std::shared_ptr<Node> previous;
    };

    class NullNode : public Node {
    public:
        virtual void setNext(Node* newNext) {};
        virtual void setPrevious(Node* newPrevious) {};
    };

node.cpp

    #include "node.h"

    std::shared_ptr<Node> Node::getNext() {
        if (nullptr == next) {
            return std::shared_ptr<Node>(new NullNode);
        }
        return next;
    }

    void Node::setNext(std::shared_ptr<Node> newNext) {
        next = newNext;
    }

    std::shared_ptr<Node> Node::getPrevious() {
        if (nullptr == previous) {
            return std::shared_ptr<Node>(new NullNode);
        }
        return previous;
    }

    void Node::setPrevious(std::shared_ptr<Node> newPrevious) {
        previous = newPrevious;
    }

main.cpp

    #include "linkedlist.h"

    void addToList() {
        LinkedList list;
        for (int i = 0; i < 100; ++i) {
            list.addNode(i);
        }
        for (int i = 99; i >= 0; ++i) {
            list.removeNode(i);
        }
    }

    int main() {
        addToList();
    }

I want to understand where did I go wrong - is it with the return of the shared_ptr's,

is it the choice of the shared_ptr against weak / unique ?

And of course - how do I make this code sample work properly .

for (int i = 99; i >= 0; ++i) {
    list.removeNode(i);
}

When i starts out as 99 and you only add to it ( ++i ), bad things are probably going to happen before it overflows. You probably meant --i .

You should consider writing it like this instead:

for (int i = 0; i < 100; ++i) {
    list.removeNode(0);
}

Or:

while (!list.empty()) list.removeNode(0);

The last way requires you to expose the size of the container or add the requsite empty() function to test if the list is empty.


If you had run your program in a debugger, it would have helped you discover this problem on your own. You should learn how to use a debugger :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM