如何用C ++中的模板类处理内存泄漏?
在这段代码中,我定义了4个模板类:
node
和班级linked_list
构成双重链接列表item
和班级bag
只是构成另一个双重链接列表这些模板类旨在处理各种类的对象。
在main函数中,我首先创建了一个linked_list<string>
和一个bag<int>
,一切都很好。
但是当我尝试制作bag<linked_list<string>>
时,会出现问题。
我试图回过头来看看发生了什么,我在类push_back
的函数bag
中看到了,linked_list
的析构函数被调用,删除了输入中的所有数据{ {1}}。我不知道为什么会这样。
请注意,我覆盖了所有类的析构函数,并在main函数中调用v
以防止内存泄漏。
它确实可以防止className.~className()
和ls_1
内存泄漏。
我不知道我的代码的哪一部分是错的。有人可以帮帮我吗?
bag_1
答案 0 :(得分:3)
实施node
,linked_list
,item
,bag
复制构造函数和作业,或将其声明为已删除。编译器生成的默认版本不会执行深层复制,并且在复制后会导致多个delete
个相同的对象。
阅读the rule of three/five/zero了解详情。
有点偏离主题,但是将列表节点delete
作为其兄弟姐妹是一个经典的问题:对于一个足够长的列表,它最终会递归调用~node<T>()
,直到它耗尽堆栈。这就是节点指针不能成为智能指针的原因。
修复方法是为节点设置默认析构函数,并使列表在循环中销毁节点,而不是递归。
您可能还希望将完整列表节点用作列表的头部,该列表在空时指向自身。这完全消除了nullptr
检查逻辑。
答案 1 :(得分:1)
我试着回过头来看看发生了什么,我在类包里面的函数push_back中看到,已经调用了linked_list的析构函数来擦除输入v中的所有数据
是的,发生这种情况是因为您的bag::push_back()
通过值获取其参数。这意味着它会创建您在main中创建的ls_1
的副本。您尚未指定如何&#34;复制&#34;列表,因此编译器自动生成此函数(复制构造函数)。它可以这样做,因为你的linked_list
只包含两个指针,所以编译器假设(因为你没有告诉它)复制指针是生成linked_list
副本所必需的。 。不幸的是,这是不正确的。
您现在有两个管理相同内容的列表:ls_1
中的原始main()
和v
中的函数参数push_back()
- 它们都包含相同的指针。
然后在你的item
构造函数中再次发生同样的事情:你创建一个列表的本地副本,其中包含与前两个相同的指针。
现在有几个列表对象指向相同的数据。一旦死亡,每个人都会试图销毁数据。这会导致未定义的行为。
要纠正这个问题,您需要弄清楚列表的复制应该如何工作。这是(部分)rule linked in the other comment的内容:如果类的析构函数不是很简单(即编译器生成的版本不够,很可能是因为你需要释放像分配的内存这样的资源) ,你应该/必须始终关心如何处理被复制的类。您需要指定(或禁止)可以调用类似行为的行为(赋值,复制构造函数以及在较新的C ++中移动版本)的各种机制。