双向链表中的智能指针

Smart pointers in doubly linked list

我正在尝试在双向链表中实现智能指针(大学任务)。在此之前,我已经用原始指针在纯 C 中完成了相同的任务。 问题是当我通过 addNode() 将新节点添加到列表中超过两次时我崩溃了(我使用 CodeLite(g++),Windows 10 64 位)。我假设问题是我的内存管理(节点和列表的析构函数)。但我觉得我没有足够的资格来解决这个问题。因此,我们将不胜感激。

#include <stdlib.h>
#include <iostream>
#include <memory>

using namespace std;

template <typename T>
struct Node       {

    T Value;
    weak_ptr<Node<T>> prev;
    shared_ptr<Node<T>> next;

    ~Node() {
        while (next){
            prev = next->next;
            next.reset();
            next = prev.lock();
        }
    }

 };


template<typename T>
class List 
{public:  

     shared_ptr<Node<T>> start;
     weak_ptr<Node<T>> end;
     int size;

 public:
     List(): size(0){};
     ~List();

     void addNode (T value);

 };


template <typename T> List<T>::~List() 
 {   
     cout<<"List destructor"<<endl;
     while (start){
         auto sp = end.lock();
         end = start->next;
         start.reset(sp.get());
     }
 }

template <typename T> void List<T>::addNode(T value){
    Node<T>* nd = new Node<T>;

    if (size==0){
        start.reset(nd);
        start->Value = value;
        end = start;

    }

    else{
        auto sp = end.lock();
        auto sp2 = end.lock();
        sp->next.reset(nd);
        sp.reset(sp->next.get());
        sp->prev = sp2;
        sp->Value = value;
        cout<<"Value size is "<<size<<" "<<sp->Value<<endl;
        end = sp;

    }

    size++;
    return;
}




int main ()
{
 system("CLS");

  string a;
  string b;
  string c;

  a = "1 test";
  b = "2 test";
  c = "3 test";


  List<string> ls;
  ls.addNode(a);
  ls.addNode(b);
  ls.addNode(c);

  return 0;

}

使用智能指针的要点是自动内存管理,因此您的 ListNode 析构函数不仅实现不佳而且多余。只需删除它们(或将它们清空)。您唯一的任务就是正确实施 addNode()

template <typename T> void List<T>::addNode(T value){
    auto nd = std::make_shared<Node<T>>();
    nd->Value = value; // this should be done in Node constructor

    if (size++ == 0){
        start = nd;
    } else{
        auto sp = end.lock();
        nd->prev = sp;
        sp->next = nd;
    }
    end = nd;
}

当你通常处理智能指针时,你永远不会调用 reset()get() 方法,只有当你出于各种原因需要处理原始指针时才调用(这里不是这种情况)。

注意:如评论中所述,虽然空析构函数可以正常工作,但由于递归调用,长列表可能会出现问题,因此您可能只想实现 List 析构函数以避免这种情况。同样,这应该在不使用 reset()get() 的情况下完成,只需正常使用智能指针即可:

~List()
{
    while( start )
       start = start->next;
}