C++ STL list 容器底层实现详解
在掌握了 list 的基本用法后,深入理解其底层机制对编写高性能 C++ 代码至关重要。list 基于双向循环链表实现,通过哨兵节点简化边界处理,这也是它区别于 vector 和 deque 的核心特征。
核心数据结构
list 的底层主要由三个部分组成:存储数据的节点 list_node,封装指针的迭代器 list_iterator,以及管理整体逻辑的 list 类。
1. 节点设计 (list_node)
双向链表的每个节点需要存储数据、前驱指针和后继指针。为了减少重复代码,通常会将结构体重命名为 Node。
template<class T> struct list_node {
typedef list_node<T> Node;
T _data; // 存储的数据
Node* _prev; // 前驱指针
Node* _next; // 后继指针
};
这里有个关键点:使用哨兵节点(Dummy Head)。这意味着链表头尾不直接指向有效数据,而是指向一个特殊的空节点。这样在插入或删除首尾元素时,就不需要单独判断是否为空,统一了逻辑。
2. 迭代器封装 (list_iterator)
迭代器的本质是对指针的封装。为了让普通迭代器和常量迭代器共用一套代码,我们使用了模板参数来区分引用类型和指针类型。
template<class T, class Ref, class Ptr>
struct list_iterator {
typedef list_node<T> Node;
typedef list_iterator<T, Ref, Ptr> Self;
Node* _pnode; // 核心成员变量,指向当前节点
};
这里的模板参数设计非常巧妙:
T:存储的元素类型。Ref:解引用operator*返回的类型(T&或const T&),决定了能否修改数据。Ptr:箭头operator->返回的类型(T*或const T*)。
这样只需一个类模板,就能同时生成可写和只读的迭代器。
3. 容器主体 (class list)
容器类负责维护整个链表的状态,最核心的成员是哨兵节点的指针 _head。
template< > {
:
list_node<T> Node;
list_iterator<T, T&, T*> iterator;
list_iterator<T, T&, T*> const_iterator;
:
Node* _head;
};


