单向链表应使用unique_ptr管理节点所有权以确保安全:节点用unique_ptr next避免悬空,链表头用unique_ptr head保障检索稳定,插入统一move转移所有权,持久化检索通过const引用或weak_ptr实现生命周期可控。
用类指针组合实现单向链表,重点不在“组合”本身,而在于让节点能安全持有、传递和复用——持久化检索与插入的前提是节点生命周期可控、所有权清晰、访问不越界。
节点设计:用 unique_ptr 管理 next,避免裸指针陷阱
别用 Node* next。裸指针不表达归属,容易悬空或重复释放。应使用 std::unique_ptr<node></node> 作为 next 成员:
- 自动管理内存:插入/删除时无需手动
delete,析构即释放整条链 - 强制移动语义:赋值或传参必须用
std::move(),杜绝浅拷贝误用 - 默认为空:
next构造即为 null,不会指向随机内存
示例节点定义:
template
struct Node {
T data;
std::unique_ptr
explicit Node(T val) : data{std::move(val)} {}
};
链表类封装:头指针用 unique_ptr,支持稳定检索
链表类持有一个 std::unique_ptr<node> head</node>,而非原始指针或引用:
- 检索操作(如
find()或get(int i))可安全遍历,因每个next非空即有效 - 插入前无需额外判空:访问
head->next前先检查head是否存在;用if (head)即可,不用if (head != nullptr) - 所有对外接口接收
std::unique_ptr<node>&</node>或值参,明确表达所有权意图
插入逻辑:分三类处理,但统一用 move 转移所有权
头插、尾插、中间插本质都是「找到前驱 → 修改其 next → 更新链状态」:
-
头插:新节点
next = std::move(head),再head = std::move(new_node) -
尾插:遍历至
curr满足!curr->next,然后curr->next = std::move(new_node) -
中间插(第 i 位):先走
i−1步到前驱,若中途curr为空则越界,直接返回
所有插入都用 std::make_unique<node>(val)</node> 创建,异常安全,无内存泄漏风险。
持久化检索的关键:不依赖外部生命周期
所谓“持久化”,不是把节点写进文件,而是指节点一旦插入链中,只要链表对象还活着,它就可被反复、安全地访问:
- 避免返回裸指针(如
Node*):改用const Node&或std::shared_ptr<const node></const>(若需共享读取) - 查找函数不修改链结构,只做 const 遍历:
const Node* find(const T& val) const - 若需长期持有某节点(比如缓存其位置),可用索引 + const 引用方式,或配合
std::weak_ptr防循环引用(当引入 shared_ptr 时)











