[英]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);
泄漏消失了。
#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.