c ++模板和析构函数问题

时间:2018-03-29 15:19:32

标签: c++ templates destructor copy-constructor

如何用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

2 个答案:

答案 0 :(得分:3)

实施nodelinked_listitembag复制构造函数和作业,或将其声明为已删除。编译器生成的默认版本不会执行深层复制,并且在复制后会导致多个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 ++中移动版本)的各种机制。