我是C ++的新手,最近一直在研究数据结构。我已通过以下方式创建链接列表:
class Random{
private:
struct Node{
int data;
Node* next;
};
}
但是我遇到了一段以下列方式做同样事情的代码:
template<Typename T>
struct Listnode {
T data;
shared_ptr<ListNode<T>> next;
};
我查了一下,发现当我们想拥有多种数据类型时,我们会使用模板。与现在一样,我们可以使用int
,double
,float
代替&#34; T&#34;。而在前一种情况下,我们只能使用int
。但是,我不明白:
Node* next
与:
相同shared_ptr<ListNode<T>> next
以及如何调用这些,我知道前者我们使用:
Node->next = new Node;
Node->data = randomdata;
它如何适用于前一种方式。这两个实现中的另一个是哪一个更好,为什么?
答案 0 :(得分:1)
T * ptr; form是声明指向存储类型为T的内存的指针的基本方法。这种指针由数组T []的基址,新T(),新T []或其他东西初始化。
正如您现在所看到的,有许多方法可以分配指针所指向的内存。这是释放所用内存的一个陷阱。你应该使用删除,删除[],还是我们指向一个甚至没有被我们分配的内存? 如果我们忘记释放已分配的内存,或尝试访问已释放的内存,该怎么办?
=&GT;使用原始指针,可以轻松发生错误!
这里的智能指针来救援!智能指针,如std :: unique_ptr, 和std :: shared_ptr为我们封装这些原始指针并处理类型安全的内存管理。因此,当超出范围时,unique_ptr中的内存将自动释放。如果不存在对它的引用,则对于shared_ptr也是如此。
我总是建议尽可能使用c ++的智能指针! 您应该使用哪种智能指针取决于您要实现的链接列表的类型(例如,如果也支持循环列表)。 顺便说一句。你有没有想过std :: vector或std :: list?
答案 1 :(得分:0)
正如Karoly Horvath所说,这不是一回事:
T*
是一个指向T
类型对象的“普通”指针,它将一个地址存储在内存中,并隐含地表示我们可以在此地址找到的对象类型(这是有用的知道例如目标记忆的大小。)std::shared_ptr<T>
是一个属于“smart-pointers”类别的对象,它被称为“智能”,因为它们可以通过跟踪存在多少个引用来管理被指向的内存到那个记忆位置。实际上,这意味着当代码在运行时不再使用时,将为您释放动态分配的内存。我想说的是,对于一个简单的链表(单链或双链),不需要使用shared_ptr
。它可能是有用的,例如对于具有动态重复结构的图形。但是为了通用性,最好使用节点的模板化版本:
template <typename T>
struct ListNode
{
T data;
ListNode<T> *next;
};
答案 2 :(得分:0)
第二种形式是&#34; smart&#34;指针。大多数使用现代c ++的代码都应该使用它们。
使用原始(非智能)指针时,您必须记住在对象超出范围时执行new / delete或new [] / delete []的配对。在构造函数/析构函数的简单情况下,它没有那么大的负担。但是,当你在一个函数中使用指针并且该函数抛出异常时,释放它会有点棘手。
有多种类型的智能指针。独特,共享和弱小。唯一身份用于一个仅在一个地方使用的关闭对象(如对象或函数)。共享用于多个对象使用相同指针/资源的情况,并且当指针的最后一个所有者超出范围时,您只想调用已分配对象的析构函数。 Weaks用于资源由其他人管理的情况,并且指向的资源应该在具有弱指针的对象超出范围之后继续存在(它们也需要用于避免阻止GC并导致内存泄漏的循环分配)。 / p> 智能指针是一件好事,你应该阅读它们(Stroustrups书很棒)。现在很少有人需要裸指针。
答案 3 :(得分:-1)
首先让我们拿走一些垃圾:
有上述警告:
std::shared_ptr
是一个更智能的指针&#39;包装一个原始指针(通常通过调用operator new
生成)并将RAII样式语义添加到混合中,同时允许底层对象的多个持有者引用内容而不会消失。 (如果使用得当。)
链接列表只是&#39;程序遵循(希望但不要求)同类型而不移动数据的约定。使用(&#39;旧学校&#39;而不是错误的)链接列表,所有链接管理都是您的责任。忘记,或分散注意力,忘记&#39;释放资源。这是导致许多夜晚的调试和令人烦恼的事情被称为“内存泄漏”的原因。
混合&#39;模板链接列表&#39;是更好的&#39;因为资源管理责任减少了。它没有消除。它将有助于减少忘记删除已分配节点的内存泄漏类型。它不会消除内存泄漏&#39;这是由循环引用引起的。 (在这种情况下,需要一个外部演员来打破循环链,并且在真正的代码中可能会非常复杂。)
std::shared_ptr
已定义运营商,允许您假装&#39;您正在与std::shared
指针正在管理的内容进行交互。以这种方式,在视觉上代码看起来大致相同,但该类(或可能)代表您隐藏一点复杂性。 (指针检查等)
哪个更好? IMO也不是。但是只要在这两者之间做出选择,我绝对会选择更智能的指针&#39;版本超过“手册”自己做的事情&#39;在大多数情况下,VAST风格。
如果是我,我会选择另一个容器。但是,如果你的意图要了解如何这些容器的基本原理(这是一件好事!),这并不是你想要听到的答案。 。 :-)