MST
星途 面试题库

面试题:C++ 智能指针在复杂数据结构中的内存管理

假设有一个复杂的数据结构,例如一个包含双向链表节点的类,每个节点可能持有指向其他节点的指针。请设计一个使用智能指针(std::shared_ptr和std::weak_ptr)的方案,来保证在这个双向链表结构中,节点的添加、删除和遍历操作都能正确管理内存,同时避免循环引用导致的内存泄漏问题,并说明在不同操作中选择不同智能指针类型的原因。
41.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 设计方案
    • 节点类定义
#include <memory>

class Node;
using NodePtr = std::shared_ptr<Node>;
using WeakNodePtr = std::weak_ptr<Node>;

class Node {
public:
    int data;
    NodePtr next;
    WeakNodePtr prev;

    Node(int value) : data(value) {}
};
  • 添加节点操作
void addNode(NodePtr& head, int value) {
    NodePtr newNode = std::make_shared<Node>(value);
    if (!head) {
        head = newNode;
    } else {
        NodePtr current = head;
        while (current->next) {
            current = current->next;
        }
        current->next = newNode;
        newNode->prev = current;
    }
}
  • 删除节点操作
void deleteNode(NodePtr& head, int value) {
    NodePtr current = head;
    NodePtr prevNode;
    while (current && current->data != value) {
        prevNode = current;
        current = current->next;
    }
    if (current) {
        if (prevNode) {
            prevNode->next = current->next;
            if (current->next) {
                current->next->prev = prevNode;
            }
        } else {
            head = current->next;
            if (head) {
                head->prev.reset();
            }
        }
        // 由于没有其他强引用,current会自动释放其内存
    }
}
  • 遍历操作
void traverse(NodePtr head) {
    NodePtr current = head;
    while (current) {
        std::cout << current->data << " ";
        current = current->next;
    }
    std::cout << std::endl;
}
  1. 智能指针类型选择原因
    • std::shared_ptr
      • 用于表示对节点的“拥有权”。在添加节点时,使用std::make_shared创建新节点,这样能更高效地管理内存。在双向链表中,next指针使用std::shared_ptr,因为它需要保持对下一个节点的强引用,以确保下一个节点在使用过程中不会被意外释放。例如在遍历链表时,current = current->next,如果next不是强引用,下一个节点可能在遍历到之前就被释放了。
    • std::weak_ptr
      • prev指针使用std::weak_ptr,这是为了避免循环引用。在双向链表中,如果prev也使用std::shared_ptr,当两个节点互相指向对方时(例如节点A的next指向节点B,节点B的prev指向节点A),会形成循环引用,导致内存泄漏。std::weak_ptr不增加引用计数,它允许观察std::shared_ptr所管理的对象,但不会阻止该对象被释放。例如在删除节点操作中,当删除一个节点时,其前驱节点的next指针和后继节点的prev指针的调整,prev指针作为std::weak_ptr不会干扰节点内存的释放。