【问题标题】:Calling destructor after shallow-copy gives "Abort trap: 6" error在浅拷贝后调用析构函数会给出“Abort trap: 6”错误
【发布时间】:2020-08-03 12:54:46
【问题描述】:

所以我有一个自行实现的链表类。对于制作“深拷贝”或基本上是链表副本的复制构造函数。但是对于赋值运算符,我基本做到了

// assignment operator
linked_list& linked_list::operator=(const linked_list& L){

    // check for self assignment 
    if(this != &L){

        this->head=L.head;
        this->sz=L.sz;
    }

   return *this;    
}

这是一个“浅拷贝”,所以当我创建一个新的链表 b 并将其指向 a 时,b 中的更改将反映在 a 中。

但现在的问题是,当我调用一个动态分配节点的析构函数时,由于它们都指向同一个对象,并且其中一个析构函数在另一个之前被调用,我收到以下错误消息。

edit.out(3537,0x106bcbdc0) malloc: *** 对象 0x7fa430c018f0 错误:未分配指针被释放

edit.out(3537,0x106bcbdc0) malloc: *** 在 malloc_error_break 中设置断点进行调试 中止陷阱:6

我使用 lldb 来探查任何解决方案,但无法估计首先调用哪些对象析构函数,以及如何防止它再次被调用。

【问题讨论】:

  • 你应该阅读rule of 3/5/0
  • 执行浅拷贝的赋值运算符没有意义。如果您执行a = b,您会期望ab 包含单独的副本,而不是同时链接到一个副本。如果您想要一个副本有两个名称,您可以使用参考,如果您想在不制作副本的情况下转移一个列表的所有权,您可以移动。
  • 复制构造函数是否正常工作?如果是,您的析构函数是否正常工作?如果是,那么赋值运算符只是一个复制和 2 个交换语句,实际上与您尝试的类似,但使用 std::swap
  • 此外,正如评论所建议的那样,执行浅拷贝的赋值运算符是违反直觉的,老实说,如果复制构造函数执行非浅拷贝,则这是一个错误。执行此操作的程序员 linked_list one; linked_list two(one); 期望与 linked_list one; linked_list two; two = one; 具有相似的复制语义

标签: c++ segmentation-fault destructor shallow-copy


【解决方案1】:

如果您的复制构造函数和析构函数工作正常(意味着没有错误),那么赋值运算符可以使用copy / swap idiom 轻松编写:

#include <algorithm>
//...
linked_list& linked_list::operator=(const linked_list& L)
{
    if (this != &L)
    {
        linked_list temp(L);
        std::swap(head, temp.head);
        std::swap(sz, temp.sz);
    }
    return *this;
}

我假设headsz 是唯一的成员。如果您有其他成员,您也需要swap 这些成员。

简而言之,它的工作方式是复制传入的linked_list。然后,您只需将当前对象的内部结构换成临时副本的内部结构。然后临时副本连同旧的内部结构一起破坏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 2013-03-19
    • 2022-01-15
    • 1970-01-01
    相关资源
    最近更新 更多