代码实现
- 浅拷贝构造函数
#include <iostream>
#include <cstring>
// 链表节点类
class ListNode {
public:
char* data;
ListNode* next;
ListNode(const char* str) {
data = new char[strlen(str) + 1];
std::strcpy(data, str);
next = nullptr;
}
~ListNode() {
delete[] data;
}
};
// 包含链表的类
class LinkedListClass {
private:
ListNode* head;
public:
LinkedListClass() : head(nullptr) {}
// 浅拷贝构造函数
LinkedListClass(const LinkedListClass& other) {
head = other.head;
}
~LinkedListClass() {
while (head != nullptr) {
ListNode* temp = head;
head = head->next;
delete temp;
}
}
};
- 深拷贝构造函数
// 深拷贝构造函数
LinkedListClass::LinkedListClass(const LinkedListClass& other) : head(nullptr) {
if (other.head == nullptr) {
return;
}
ListNode* current = other.head;
head = new ListNode(current->data);
ListNode* newCurrent = head;
current = current->next;
while (current != nullptr) {
newCurrent->next = new ListNode(current->data);
current = current->next;
newCurrent = newCurrent->next;
}
}
不同拷贝方式对数据结构的影响
- 浅拷贝
- 数据结构关系:浅拷贝构造函数只是简单地复制了链表头指针,使得新对象和原对象的链表头指向同一个链表。这意味着两个对象共享链表节点的内存。
- 内存管理问题:当其中一个对象销毁链表时,另一个对象的链表也会被销毁,因为它们指向相同的内存。如果在一个对象销毁后,另一个对象还试图访问链表,就会导致悬空指针,引发未定义行为。
- 深拷贝
- 数据结构关系:深拷贝构造函数会创建一个全新的链表,每个节点的内存都是重新分配的,新链表和原链表相互独立,拥有各自的内存空间。
- 内存管理问题:深拷贝避免了共享内存带来的问题,每个对象独立管理自己链表的内存,对象销毁时不会影响其他对象的链表。但是,深拷贝会消耗更多的内存和时间,因为需要为每个节点重新分配内存并复制数据。
业务需求下的拷贝方式选择
- 当追求效率且数据共享安全时:如果业务场景允许两个对象共享链表数据,并且不会出现一个对象销毁链表而另一个对象还需要使用的情况,浅拷贝是合适的选择。例如,在一些只读场景下,多个对象只是用于查看链表数据,不会对链表进行修改或销毁操作,浅拷贝可以节省内存和时间。
- 当需要数据隔离时:如果每个对象需要独立管理自己的链表数据,例如一个对象可能会修改链表结构或销毁链表,就必须使用深拷贝。这样可以确保每个对象的数据完整性和独立性,避免因共享内存带来的数据冲突和悬空指针问题。