free():调用赋值运算符时在 tcache 2 中检测到双重释放

Posted

技术标签:

【中文标题】free():调用赋值运算符时在 tcache 2 中检测到双重释放【英文标题】:free(): double free detected in tcache 2 on calling assignment operator 【发布时间】:2021-12-19 16:42:55 【问题描述】:

我刚刚问了一个非常相似的问题,但我已经回答了这个问题的答案,我只是看不出这次我做错了什么。我正在研究一个使用链表实现 c++ list<int> 的大学项目。我正在研究赋值运算符,这就是我目前所拥有的。

Linkedlist &Linkedlist::operator=(const Linkedlist &l) 
    clear();
    if(l.empty())
    
        return *this;
    
    Node *iterRight = l.head;
    head = new Node;
    Node *iterLeft = head;
    while(iterRight != NULL)
    
        iterLeft -> data = iterRight -> data;
        iterLeft -> next = new Node;
        iterLeft -> next -> prev = iterLeft;
        iterLeft = iterLeft -> next;
        iterRight = iterRight -> next;
    
    return *this;

当我运行时,assingment 运算符确实可以将数据从一个列表复制到另一个列表,但我在运行后得到了这个 -

free(): double free detected in tcache 2

我不明白我是如何不当使用指针的。谁能告诉我我做错了什么?

编辑:析构函数也可能有用。

```
Linkedlist::~Linkedlist() 
Node *del;
while(head != NULL)

    del = head;
    head = head -> next;
    delete del;


编辑:抱歉,我对 Stack Overflow 很陌生。如果我对 MRE 的理解正确,这是要重现的最少代码量(上面的所有内容都加上了我的主程序和我的构造函数)。

int main() 
Linkedlist a(20);
Linkedlist b = a;
return 0;

Linkedlist::Linkedlist(unsigned int n) 
    size = n;
    tail = NULL;
    head = new Node;
    Node *iter = head;
    for(int i = 0; i < n; i++)
    
        iter -> data = i;
        iter -> next = new Node;
        iter -> next -> prev = iter;
        iter = iter -> next;
    
    tail = iter -> prev;
    tail -> next = NULL;

调用 Linkedlist a 的构造函数不会崩溃,它只会在我调用赋值时崩溃。我在 valgrind 中运行我的程序,但由于我在内存管理方面相当陌生,所以我不太确定我在看什么。它在我的析构函数中显示了我和无效的 free(),但我找不到它之前已经释放的位置。

【问题讨论】:

请提供minimal reproducible example;代码可能在其他地方。如果您遇到困难,请通过 valgrind 运行您的程序或在打开地址清理程序的情况下构建(它们都会告诉您数据首先在哪里delete'd)。 仅此代码不会产生双重释放。没有minimal reproducible example,您只能猜测要显示的代码,而我们只能猜测未显示的代码。我目前的猜测? Rule of three. 对不起@DrewDormann,我想我用一个最小的可重现示例编辑了它。 您在此处显示的代码does not compile,因此无法重现您描述的消息。我非常有信心您仍然没有向我们展示更多代码。您的主要功能确实暗示了我之前的猜测,即您违反了我们尚未显示的代码中的Rule of Three。 【参考方案1】:

行:

Linkedlist b = a;

调用复制构造函数,而不是赋值运算符。如果您没有提供复制构造函数,那么编译器生成的只会复制head 指针。然后,在销毁过程中,相同的head 将从列表a 和列表b 中删除,从而导致“双重释放”。

【讨论】:

以上是关于free():调用赋值运算符时在 tcache 2 中检测到双重释放的主要内容,如果未能解决你的问题,请参考以下文章

使用 macOS High Sierra 时在 C 中使用 while(free) 而不是 while(true)

c++面试题1

赋值函数(运算符重载)

派生赋值运算符从基础调用

fastbin_tcache

17.tcache_dup