MST

星途 面试题库

面试题:C++浅拷贝与深拷贝在复杂数据结构类中的应用

考虑一个C++类,它包含一个链表成员。链表节点类也有动态分配的内存成员(如字符串)。请分别实现该类的浅拷贝构造函数和深拷贝构造函数,并分析在不同场景下使用这两种拷贝方式对整个数据结构的影响,以及如何在不同的业务需求下选择合适的拷贝方式。
47.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

代码实现

  1. 浅拷贝构造函数
#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;
        }
    }
};
  1. 深拷贝构造函数
// 深拷贝构造函数
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;
    }
}

不同拷贝方式对数据结构的影响

  1. 浅拷贝
    • 数据结构关系:浅拷贝构造函数只是简单地复制了链表头指针,使得新对象和原对象的链表头指向同一个链表。这意味着两个对象共享链表节点的内存。
    • 内存管理问题:当其中一个对象销毁链表时,另一个对象的链表也会被销毁,因为它们指向相同的内存。如果在一个对象销毁后,另一个对象还试图访问链表,就会导致悬空指针,引发未定义行为。
  2. 深拷贝
    • 数据结构关系:深拷贝构造函数会创建一个全新的链表,每个节点的内存都是重新分配的,新链表和原链表相互独立,拥有各自的内存空间。
    • 内存管理问题:深拷贝避免了共享内存带来的问题,每个对象独立管理自己链表的内存,对象销毁时不会影响其他对象的链表。但是,深拷贝会消耗更多的内存和时间,因为需要为每个节点重新分配内存并复制数据。

业务需求下的拷贝方式选择

  1. 当追求效率且数据共享安全时:如果业务场景允许两个对象共享链表数据,并且不会出现一个对象销毁链表而另一个对象还需要使用的情况,浅拷贝是合适的选择。例如,在一些只读场景下,多个对象只是用于查看链表数据,不会对链表进行修改或销毁操作,浅拷贝可以节省内存和时间。
  2. 当需要数据隔离时:如果每个对象需要独立管理自己的链表数据,例如一个对象可能会修改链表结构或销毁链表,就必须使用深拷贝。这样可以确保每个对象的数据完整性和独立性,避免因共享内存带来的数据冲突和悬空指针问题。