簡體   English   中英

LinkedLists 的 LinkedList 的析構函數

[英]Destructor for LinkedList of LinkedLists

對於我的一個編程課程中的作業,我們必須制作一個鄰接表,它是一個鏈表的鏈表,看起來像這樣。

A->B->C

B->A->D

C->D

D->A->B->C

我在嘗試釋放析構函數中分配的內存時遇到了內存泄漏問題。 我一直試圖弄清楚它有一段時間了,但還沒有找到/想出任何有效的解決方案。

另外,請忽略頭文件中包含的實現。 我們被告知可以完成這項任務。

Valgrind 錯誤消息:

==2316== 堆摘要:
==2316== 在退出時使用:2 個塊中的 48 個字節
==2316== 總堆使用量:3 次分配,1 次釋放,已分配 64 字節
==2316==
==2316== 1 個塊中的 48(32 個直接,16 個間接)字節在丟失記錄 2 of 2 中肯定丟失
==2316== 在 0x4C2B0E0:operator new(unsigned long)(在 /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2316== 由 0x4012EE: main (main.cpp:34)
==2316==
==2316== 泄漏摘要:
==2316== 肯定丟失了:1 個塊中的 32 個字節
==2316== 間接丟失:1 個塊中的 16 個字節
==2316== 可能丟失:0 個塊中的 0 個字節
==2316== 仍然可達:0 個塊中的 0 個字節
==2316== 被抑制:0 個塊中的 0 個字節
==2316==
==2316== 對於檢測到和抑制的錯誤的計數,重新運行: -v
==2316== 錯誤摘要:1 個上下文中的 1 個錯誤(禁止:0 中的 0)

這是我正在使用的一些代碼(用 gcc c++11 編譯):
鏈表.h

#ifndef LINKEDLIST_H
#define LINKEDLIST_H

template<typename T> struct Node
{
    T data;
    Node<T>* next;
};

template<typename T> class LinkedList
{
private:
    Node<T>* head;
    Node<T>* tail;
    Node<T>* curr;
    unsigned int size;

    void insertAtHead(T val)
    {
        Node<T>* temp = new Node<T>;
        temp->data = val;
        temp->next = nullptr;
        head = temp;
        tail = temp;
        curr = temp;
        size++;
    }

public:
    LinkedList()
    {
        head = nullptr;
        tail = nullptr;
        curr = nullptr;
        size = 0;
    }

    ~LinkedList()
    {
        Node<T>* nodePtr = head;
        Node<T>* temp;

        while (nodePtr != nullptr)
        {
            temp = nodePtr;
            nodePtr = nodePtr->next;
            delete temp;
        }

        size = 0;
    }

    void insertAtTail(T val)
    {
        if (head == nullptr)
            insertAtHead(val);
        else
        {
            Node<T>* temp = new Node<T>;
            temp->data = val;
            curr->next = temp;
            temp->next = nullptr;
            tail = temp;
            curr = temp;
            size++;
        }
    }
    // returns the value at the node location passed if it exists within the
    // linked list, otherwise nothing is returned
    T get(int location)
    {
        // std::cout << "size: " << size << std::endl;

        if (location >= 0 && location <= size)
        {
            Node<T>* temp = head;
            unsigned int counter = 0;

            while (counter != location)
            {
                temp = temp->next;
                counter++;
            }

            return temp->data;
        }
    }
};
#endif // LINKEDLIST_H

主程序

#include "linkedlist.h"

int main()
{
    LinkedList<LinkedList<int>*> matrix;
    matrix.insertAtTail(new LinkedList<int>);
    matrix.get(0)->insertAtTail(6);

    return 0;
}

並非所有get(location)路徑都返回值。

使用編譯器的警告來查找此類問題(例如-Wall -Wextra -pedantic )。

另外,請確保在構造時初始化所有成員。

struct Node
{
    T data {};
    Node<T>* next = nullptr;
};

Node<T>* head = nullptr;
Node<T>* tail = nullptr;
Node<T>* curr = nullptr;

更新

在更仔細地查看之后,確實您永遠不會刪除作為外部列表中數據T的指針。 由於您的列表不知道T是否是(擁有的)指針,因此它無法決定刪除。

通常,我們使用智能指針包裝器來解決這個問題。 在您的情況下,您可能不會“被允許”使用它,因此,請在刪除列表節點之前編寫額外的循環來刪除數據指針。

建議修復

這是一個重新設計的示例,它可以選擇采用NodeFree類型模板參數,因此您可以為外部列表傳入std::default_delete<T>

template <typename T> struct DefaultNodeFree {
    void operator()(T &) const {}
};

template<typename T, typename NodeFree = DefaultNodeFree<T> > class LinkedList
{
private:

    struct Node {
        T data {};
        Node* next = nullptr;

        ~Node() { NodeFree()(data); }
    };

所以你可以像這樣使用它:

typedef LinkedList<int> inner;
LinkedList<inner*, std::default_delete<inner> > matrix;

matrix.insertAtTail(new LinkedList<int>);
matrix.get(0)->insertAtTail(6);

泄漏消失了。

現場演示

住在 Coliru

#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <cassert>
#include <memory>

template <typename T> struct DefaultNodeFree {
    void operator()(T &) const {}
};

template<typename T, typename NodeFree = DefaultNodeFree<T> > class LinkedList
{
private:

    struct Node {
        T data {};
        Node* next = nullptr;

        ~Node() { NodeFree()(data); }
    };

    Node* head = nullptr;
    Node* tail = nullptr;
    Node* curr = nullptr;
    unsigned int size;

    void insertAtHead(T val)
    {
        Node* temp = new Node;

        temp->data = val;
        temp->next = nullptr;

        head = temp;
        tail = temp;
        curr = temp;

        size++;
    }

public:
    LinkedList()
    {
        head = nullptr;
        tail = nullptr;
        curr = nullptr;
        size = 0;
    }

    ~LinkedList()
    {
        Node* nodePtr = head;

        while (nodePtr != nullptr)
        {
            Node* temp = nodePtr;
            nodePtr = nodePtr->next;
            delete temp;
            size -= 1;
        }

        assert(size == 0);
    }

    void insertAtTail(T val)
    {
        if (head == nullptr)
            insertAtHead(val);
        else
        {
            Node* temp = new Node;
            temp->data = val;
            curr->next = temp;
            temp->next = nullptr;
            tail = temp;
            curr = temp;
            size++;
        }
    }

    // returns the value at the node location passed if it exists within the
    // linked list, otherwise nothing is returned
    T get(unsigned location)
    {
        // std::cout << "size: " << size << std::endl;

        if (location >= 0 && location <= size)
        {
            Node* temp = head;
            unsigned int counter = 0;

            while (counter != location)
            {
                temp = temp->next;
                counter++;
            }

            return temp->data;
        }

        return {};
    }
};
#endif // LINKEDLIST_H

int main()
{
    typedef LinkedList<int> inner;
    LinkedList<inner*, std::default_delete<inner> > matrix;

    matrix.insertAtTail(new LinkedList<int>);
    matrix.get(0)->insertAtTail(6);
}

根據我的經驗,當你使用模板時,你可以在同一個頭文件中實現它們,但你必須將實現與聲明分開。

一個常見的解決方案是在頭文件中編寫模板聲明,並在頭文件的末尾包含實現。 在這里閱讀最高投票為什么模板只能在頭文件中實現?

我不確定這是否是您的問題,但上次我嘗試按照您的方式實現模板時,我的程序根本無法運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM