Создание связанного списка shared_ptr из необработанного указателя - PullRequest
0 голосов
/ 11 мая 2019

Я пытаюсь скопировать мой список ссылок, начиная с заголовка на shared_ptr, как часть моего remove метода. По какой-то причине инициализация моего shared_ptr из необработанного указателя полностью удаляет мой связанный список и заменяет значение заголовка на 11619904 (это адрес чего-то, что я испортил в памяти? Интересно, что вы видите в моем звонке на std::cout << "shared data " << current->data() << "\n"; в пределах remove, чтобы увидеть, что происходит с данными, заголовок печатается как содержащий 0 правильно.

Эта ошибка подробно описана ниже с моей командой компиляции и исходным кодом для Main и объекта LinkedList:

> g++ -std=c++17 main.cpp && ./a.out

    Smart ptr
    0 -> 1 -> 2 -> 3 -> 4 -> nullptr
    shared data 0
    11619904 -> nullptr

Главная

int main() {
    std::cout << "\nSmart ptr\n";
    LinkedListSmart linked_list_smart(0);

    for(int i=1; i<5; ++i) {
        linked_list_smart.append(i);
    }
    std::cout << linked_list_smart << '\n';

    linked_list_smart.remove(4);
    std::cout << linked_list_smart << '\n';
}

LinkedList

class LinkedListSmart
{
    private:
        class Node
        {
            private:
                int m_data;
                std::unique_ptr<Node> m_next;
            public:
                Node(int data) : m_data(data), m_next(nullptr) {}
                int data() const { return m_data; }
                Node* get_next() const {
                    Node* next = m_next.get();
                    return next;
                }
                void set_next(int data) {
                    m_next = std::make_unique<Node>(data);
                }
                Node* release_next() {
                    return m_next.release();
                }
                void reset_next(Node* next) {
                    m_next.reset(next);
                }
        };
        std::unique_ptr<Node> m_head;
    public:
        LinkedListSmart(int data) {
            m_head = std::make_unique<Node>(data);
        }
        Node* head() const {
            return m_head.get();
        }

        void append(int data) {
            if (m_head == nullptr) {
                m_head = std::make_unique<Node>(data);
            }
            Node* node = head();
            while(node->get_next()) {
                node = node->get_next();
            }
            node->set_next(data);
            node = nullptr; // without this will get Segmentation fault (core dumped)
            delete node;
        }
        void remove(int data) {
            if (m_head == nullptr) { return; }

            Node* n = new Node(0);
            n = head();
            std::shared_ptr<Node> current(n);
            std::shared_ptr<Node> previous = nullptr;
            std::cout << "shared data " << current->data() << "\n";
        }
        friend std::ostream& operator<<(std::ostream& os, const LinkedListSmart& linked_list_smart) {
            auto node = linked_list_smart.head();

            if(node == nullptr) {
                os << "List is empty\n";
            }
            else {
                while(node) {
                    os << node->data() << " -> ";
                    node = node->get_next();
                }
            }
            os << "nullptr";
            delete node;

            return os;
        }
};

Ответы [ 2 ]

1 голос
/ 12 мая 2019

На данный момент std::cout << "shared data " << current->data() << "\n"; current и m_head имеют один и тот же необработанный указатель, и оба они действительны.Но в конце remove() current уничтожает и удаляет необработанный указатель.Теперь m_head содержит висячий указатель.Когда linked_list_smart уничтожено, m_head удаляет (уже удаленный) указатель.Также у вас есть утечка памяти здесь:

Node* n = new Node(0); n = head();

И, как указал @QuestionC, не удаляйте необработанный указатель, принадлежащий unique_ptr.

0 голосов
/ 11 мая 2019
    friend std::ostream& operator<<(std::ostream& os, const LinkedListSmart& linked_list_smart) {
        auto node = linked_list_smart.head();

        if(node == nullptr) {
            os << "List is empty\n";
        }
        else {
            while(node) {
                os << node->data() << " -> ";
                node = node->get_next();
            }
        }
        os << "nullptr";
        delete node;

        return os;
    }

delete node в конце этой функции неверно. Вы удаляете последний элемент списка, когда вызываете operator<<, и это повреждает структуру данных. Кроме того, вы вызываете delete в памяти, которая управляется unique_ptr, что неправильно.

delete имеет смысл использовать только в сочетании с new для ручного управления памятью. Чтобы правильно реализовать связанный список в C ++, вам потребуется ручное управление памятью, но, конечно, не в методе operator<<.

...