C++析构函数中的双精度free

9lowa7mx  于 2022-11-19  发布在  其他
关注(0)|答案(1)|浏览(212)

我正在尝试用C++实现一个链表。链表包含一个指向堆上分配的节点类型的指针
代码如下:

#include <memory>

template<typename T>
class node {
public:
    node(T v) : value(v) {}
    
    ~node() = default;

    T value;
    node *next;
};

template<typename T, class Allocator = std::allocator<node<T>>>
class linked_list {
private:
    node<T>* head;
    Allocator alloc;

public:
    linked_list() : head(nullptr) {}

    ~linked_list() {
        for (auto start = head; start != nullptr; start = start->next) {
            start->~node();
            alloc.deallocate(start, 1);
        }
    }

    void push_back(T value) {
        node<T> *new_node = alloc.allocate(1); 
        new (new_node) node<T>(value);

        if (head == nullptr) {
            head = new_node;
            return;    
        }

        head->next = new_node;
        head = new_node;
    }
};

在main.cpp中:

#include "linked_list.hpp"

int main() {
    linked_list<int> a;

    a.push_back(4);
    a.push_back(5);

    return 0;
}

当我运行它的时候,我在缓存T2中检测到了双重释放。我在析构函数上做错了什么?

7d7tgy0s

7d7tgy0s1#

这是新手常见的错误。您修改了循环控制变量。

for (auto start = head; start != nullptr; start = start->next)
{
     start->~node();
     alloc.deallocate(start, 1);
}

您修改了for循环体中的start(删除内存),然后试图取消引用刚刚在其延续表达式中删除的指针。BOOM!您很幸运,运行时库足够聪明,能够捕捉到这一点,并给予您“双重释放”错误,而不是发射核导弹。
这是while循环优于for循环的一个地方。

while (head)
{
   auto to_del = head;
   head = head->next; 
   to_del ->~node();
   alloc.deallocate(to_del, 1);
}

我省略了很多关于你的过时技术的评论,因为它们与你所遇到的问题无关,但是如果你真的想用一种不同的分配器来代替,你应该考虑使用allocator_traits来分配、构造、销毁和释放你的元素。
还有其他一些问题,比如push_back在插入新节点的位置上完全错误。用new_node->next = head;替换head->next = new_node;至少可以防止程序孤立所有的新节点。

相关问题