记一下以前手动写链表的坑,也是在数据结构和算法中能够看到这种原始的存在,现代C++还是利用好写好的STL里面的内容为好,别人已经集成好的内容大概率是比自己手写的结构和算法更高效的。
RAII-对象离开作用域就会销毁
#include <iostream>
struct Node {
int data;
Node* next;
Node(int value) : data(value), next(nullptr) {}
};
class LinkedList {
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
// 在链表头部插入元素
void insert(int value) {
Node* newNode = new Node(value);
newNode->next = head;
head = newNode;
}
// 遍历链表并打印元素
void print() {
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
}
// 删除链表中的所有节点,释放内存
~LinkedList() {
Node* current = head;
while (current != nullptr) {
Node* nextNode = current->next;
delete current;
current = nextNode;
}
}
};
int main() {
LinkedList myList;
// 在链表头部插入元素
myList.insert(3);
myList.insert(2);
myList.insert(1);
// 遍历链表并打印元素
myList.print();
// 在main函数结束时,LinkedList的析构函数会自动释放链表中的内存
return 0;
}
对于这个链表的实现,当离开作用域时,链表对象 myList
将会被销毁,从而触发 LinkedList
类的析构函数。
在析构函数中,它会遍历整个链表,并释放每个节点的内存,确保没有内存泄漏。在这个例子中,析构函数的实现中有一个循环,它会依次删除每个节点,并将下一个节点赋给 current
,直到遍历完整个链表。
所以,在 main
函数结束时,当 myList
对象离开作用域时,析构函数将被调用,链表中的所有节点都将被正确释放,内存将被回收。
这种自动释放内存的机制是 C++ 中的一项重要特性,称为 RAII(资源获取即初始化),通过对象的生命周期来管理资源的获取和释放。在这个例子中,通过定义 LinkedList
类的析构函数,在对象销毁时自动释放链表节点的内存,避免了手动管理内存的繁琐和潜在的错误。
手动释放内存
如果你希望在另外一个作用域中使用完链表后再手动释放内存,你可以定义一个单独的函数来进行释放操作,而不是依赖析构函数自动释放内存。
你可以在 LinkedList
类中添加一个公有的成员函数,例如 void release()
,在这个函数中实现释放链表节点的操作。这样,你就可以在需要的时候手动调用myList.release()
这个函数来释放内存,而不是依赖对象的析构函数。
class LinkedList {
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
// 在链表头部插入元素
void insert(int value) {
Node* newNode = new Node(value);
newNode->next = head;
head = newNode;
}
// 遍历链表并打印元素
void print() {
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
}
// 手动释放链表中的所有节点的内存
void release() {
Node* current = head;
while (current != nullptr) {
Node* nextNode = current->next;
delete current;
current = nextNode;
}
head = nullptr; // 清空头指针
}
};