使用C+中的模板实现链表+; 我是C++新手,最近一直在学习数据结构。我以以下方式创建了链接列表: class Random{ private: struct Node{ int data; Node* next; }; } template<Typename T> struct Listnode { T data; shared_ptr<ListNode<T>> next; };

使用C+中的模板实现链表+; 我是C++新手,最近一直在学习数据结构。我以以下方式创建了链接列表: class Random{ private: struct Node{ int data; Node* next; }; } template<Typename T> struct Listnode { T data; shared_ptr<ListNode<T>> next; };,c++,c++11,C++,C++11,但我遇到了一段代码,它以以下方式执行相同的操作: class Random{ private: struct Node{ int data; Node* next; }; } template<Typename T> struct Listnode { T data; shared_ptr<ListNode<T>> next; }; 同: shared_ptr<

但我遇到了一段代码,它以以下方式执行相同的操作:

class Random{
private:
   struct Node{
          int data;
          Node* next;
         };
} 
template<Typename T>
struct Listnode {
      T data;
      shared_ptr<ListNode<T>> next;
};
同:

shared_ptr<ListNode<T>> next

对于前一种方式,它是如何工作的。这两种实现中的另一件事是,哪一种更好,为什么呢?

首先让我们把一些垃圾清理掉:

  • 学习和理解链表的原始实现是很好的,因为您将在生产代码中遇到它们(出于许多好的或坏的原因)
  • 如果你必须在代码中使用“侵入性”链表,模板和“更智能的指针”将为你省去麻烦。(海事组织)
  • 集合类/模板几乎总是为您提供更好的服务
  • 根据上述警告:

    std::shared_ptr
    是一个“更智能的指针”,它包装了一个原始指针(通常通过调用
    操作符new
    生成),并在混合中添加了样式语义,以及一个契约,该契约允许基础对象的多个持有者引用内容而不会消失。(正确使用时。)


    链表“只是”程序遵循的一种约定(希望是,但不要求是)同质类型,而无需移动数据。使用('old school',不错)链接列表,所有链接管理都是您的责任。这是非常容易忘记,或分心和'忘记'免费资源。这是许多晚上调试和令人讨厌的事情的原因,这些事情被称为“内存泄漏”

    混合“模板链接列表”的“更好”之处在于减少了资源管理责任。它并没有被消除。这将有助于减少忘记删除已分配节点的内存泄漏。它不会消除由循环引用引起的“内存泄漏”。(这种情况下,需要一个“外部参与者”来打破循环链,并且在“真实”代码中可能非常复杂。)

    std::shared\u ptr
    定义了允许您“假装”正在与
    std::shared
    指针管理的对象交互的运算符。这样,代码在视觉上看起来基本相同,但类(/可能)为您隐藏了一点复杂性。(指针检查等)

    哪个更好?我也没有。然而,如果在这两者之间做出选择,在绝大多数情况下,我绝对更喜欢“智能指针”版本,而不是“自己动手”风格


    如果是我,我会选择另一个容器。但是,如果您的目的是了解如何实现这些容器的基本原理(一件好事!),那么这并不是您想要听到的答案。:-)

    正如Karoly Horvath所说,这不是一回事:

    • T*
      是一个指向类型为
      T
      的对象的“普通”指针,它在内存中存储一个地址,并隐式地表示我们期望在该地址处找到的对象类型(这对于了解目标内存的大小非常有用)
    • 是属于“”类别的对象,称为“智能”,因为它们可以通过跟踪对该内存位置存在多少引用来管理所指向的内存。这实际上意味着,当代码在运行时不再使用动态分配的内存时,它将为您释放
    我想说的是,对于一个简单的链表(单链或双链),没有必要使用
    shared\u ptr
    s。例如,对于具有动态递归结构的图,它可能很有用。不过,出于通用性考虑,最好使用节点的模板版本:

    template <typename T>
    struct ListNode
    {
        T data;
        ListNode<T> *next;
    };
    
    模板
    结构列表节点
    {
    T数据;
    ListNode*下一步;
    };
    
    第二种形式是一种“智能”指针。大多数使用现代C++的代码应该使用它们。p> 使用原始(非智能)指针时,当对象超出范围时,必须记住对new/delete或new[]/delete[]进行配对。在构造函数/析构函数的过于简单的情况下,它并没有那么大的负担。但是,当您在函数中使用指针时,该函数会抛出异常,释放这些异常会变得有点棘手

    智能指针有多种类型。独特的、共享的和脆弱的。Unique用于仅在一个位置使用的一次性对象(如对象或函数)。共享用于多个对象使用同一指针/资源,并且您只希望在指针的最后所有者超出范围时调用分配对象的析构函数的情况。漏洞适用于以下情况:资源由其他人管理,并且在具有弱指针的对象超出范围后,指向的资源应该继续存在(它们还用于避免防止GC和导致内存泄漏的周期性分配)


    聪明的指针是件好事,你应该仔细阅读它们(Stroustrups的书很棒)。现在很少有需要裸指针的情况;form是一种基本方法,它声明指向一个内存的指针,该内存中包含类型为T的值。这种指针可以通过数组T[]的基地址、new T()、new T[]或其他方式初始化

    正如您现在看到的,有很多方法可以分配指针指向的内存。这是释放所用内存的陷阱之一。您应该使用delete、delete[],还是我们指向的内存甚至不是由我们分配的? 如果我们忘记释放已分配的内存,或者尝试访问已释放的内存,该怎么办

    =>使用原始指针,很容易出现错误

    这里有智能指针来拯救!像std::unique\u ptr这样的智能指针, 和std::shared_ptr为我们封装这些原始指针并处理类型安全内存管理。因此,当超出作用域时,将自动释放唯一\u ptr中的内存。相同的