简体   繁体   中英

Double free in c++ destructor

I'm trying to implement a linked list in C++. The list contains a pointer to a node type allocated on the heap

The code is as follow:

#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;
    }
};

In main.cpp:

#include "linked_list.hpp"

int main() {
    linked_list<int> a;

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


    return 0;
}

When I ran it I got double free detected in cache T2. What did I do wrong with the destructor?

This is a common newbie error. You modified your loop control variable.

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

You modified start (deleting the memory) in the for loop's body and then tried to dereference the pointer you just deleted in its continuation expression. BOOM , You are fortunate that the runtime library was smart enough to catch this and give you the "double free" error rather than, say. launch a nuclear missile.

This is one place a while loop is better than a for loop.

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

I've left out a lot of commentary about your antiquated techniques because they don't relate to the problem you're having, but if you really want to substitute in a different kind of allocator you should look into using allocator_traits for allocation, construction, destruction, and deallocation of your elements.

There are other problems, such as push_back being completely wrong as to where it inserts the new node. Replacing head->next = new_node; with new_node->next = head; will at least keep your program from orphaning all of the new nodes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM