【问题标题】:Linked list creating shared_ptr from raw pointer链表从原始指针创建 shared_ptr
【发布时间】:2019-09-29 07:17:57
【问题描述】:

我正在尝试将我的链接列表从头部复制到shared_ptr,作为我的remove 方法的一部分。出于某种原因,从原始指针初始化我的shared_ptr 完全删除了我的链表并用 11619904 替换了头值(这是我在内存中损坏的地址吗?有趣的是,你在我的在remove 中调用std::cout << "shared data " << current->data() << "\n"; 以查看数据发生了什么,head 被打印为正确包含 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';
}

链表

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;
        }
};

【问题讨论】:

  • 为什么要复制到共享指针?目前,所有共享指针所做的都是导致内存问题(如输出中的垃圾所见)。共享指针是函数的本地指针,实际上并不共享。那么为什么要介绍它们呢?

标签: c++ c++11 linked-list shared-ptr smart-pointers


【解决方案1】:

目前 std::cout &lt;&lt; "shared data " &lt;&lt; current-&gt;data() &lt;&lt; "\n"; currentm_head 拥有相同的原始指针并且两者都是有效的。但在remove() 的末尾,current 会破坏并删除原始指针。现在m_head 包含悬空指针。当linked_list_smart 破坏m_head 删除(已删除)指针。你也有内存泄漏:

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

正如@QuestionC 所指出的,不要删除unique_ptr 拥有的原始指针。

【讨论】:

  • 我永远不应该手动删除 unique_ptr 拥有的原始指针?
【解决方案2】:
    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&lt;&lt; 时,您正在删除列表的最后一个元素,这会破坏数据结构。此外,您在由 unique_ptr 管理的内存上调用 delete,这是错误的。

delete 仅与new 一起使用才有意义,用于手动内存管理。要在 C++ 中正确实现链表,您需要一些手动内存管理,但在 operator&lt;&lt; 方法中肯定不需要。

【讨论】:

  • 不,std::shared_ptr&lt;Node&gt; current(n); 正在破坏头指针。在operator&lt;&lt; node 删除时始终为nullptr。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-23
  • 1970-01-01
  • 2021-11-15
  • 2013-10-09
  • 1970-01-01
  • 2012-09-07
  • 1970-01-01
相关资源
最近更新 更多