STL list原始碼分析以及實現
阿新 • • 發佈:2019-02-01
本文主要內容如下:
1. STL list
實現的三個模組節點__list_node
,迭代器__list_iterator
以及list本身
(使用一個__list_node*代表整個連結串列)的介紹。
2. 重點分析list
的幾個核心函式,理解STL list
的實現原理,核心函式如下:
list
的建構函式基本的迭代器操作
插入操作
size, 解構函式等
3. 測試實現的基本的list
,包括基本型別如int
以及結構體。
1. STL list
實現的三個模組
1.1 STL list節點
節點定義如下:
template<typename T>
struct __list_node{
typedef __list_node* list_node_pointer;
list_node_pointer prev;
list_node_pointer next;
T data;
};
1.2 迭代器__list_iterator
迭代器的定義如下(下面先省略了iterator_category迭代器型別),迭代器主要是作為 list
內部的iterator
來使用:
template<typename T>
struct __list_iterator{
typedef __list_iterator<T> self;
typedef __list_node<T>* link_type;
link_type ptr; //成員
__list_iterator(link_type p = nullptr):ptr(p){}
.....//先省略成員函式
}
list
的迭代器需要實現的操作有:++、–、*、->、==、!=,定義如下:
T& operator *(){return ptr->data;}
T* operator ->(){return &(operator *());}
self& operator++(){
ptr = ptr->next;
return *this;
}
self operator++(int){
self tmp = *this;
++*this;
return tmp;
}
self& operator--(){
ptr = ptr->prev;
return *this;
}
self operator--(int){
self tmp = *this;
--*this;
return tmp;
}
bool operator==(const __list_iterator& rhs){
return ptr == rhs.ptr;
}
bool operator!=(const __list_iterator& rhs){
return !(*this==rhs);
}
2. list
的核心實現
2.1 list節點
的主要型別,以及成員變數
list主要的變數別名,以及成員定義如下:
template<typename T>
class SimpleList{
protected:
typedef __list_node<T> list_node;
// nodeAllocator 按照 list_node為單位分配記憶體
typedef allocator<list_node> nodeAllocator;
public:
typedef T value_type;
typedef T& reference;
typedef value_type* pointer;
typedef list_node* link_type;
typedef const value_type* const_pointer;
typedef size_t size_type;
public:
typedef __list_iterator<value_type> iterator;
private:
link_type node; // 只要一個指標,便可表示整個環狀雙向連結串列
.............//為了更清晰的看list的定義,先省略其他的函式
}
2.2 list
的建構函式
在給出list的建構函式之前,先給出,list內部的向空間配置申請節點的記憶體分配,以及在節點上面構造物件(呼叫物件的建構函式),節點返還給空間配置器,以及物件的析構(呼叫物件的解構函式)。
// 分配一個新結點(分配記憶體), 注意這裡並不進行構造,
link_type alloc_node(){
return nodeAllocator::allocate();
}
// 釋放一個結點(節點記憶體由空間配置回收)
void dealloc_node(link_type p){
nodeAllocator::deallocate(p);
}
// 產生(配置並構造)一個節點, 首先分配記憶體, 然後進行構造
link_type alloc_ctor_node(const T& val){
link_type p = alloc_node();
// 這裡要構造的是節點的data
construct(&p->data, val);
return p;
}
// 析構結點元素, 並釋放記憶體
void dealloc_dtor_node(link_type p){
destroy(&p->data);
dealloc_node(p);
}
基本的建構函式定義如下:
void empty_initialize(){
node = alloc_node(); // 配置一個節點空間,令node指向它
node->prev = node; // 令node頭尾都指向自己,不設元素值
node->next = node;
}
SimpleList(){
empty_initialize();
}
注:
explicit SimpleList(size_t n);
建構函式後面在給出
2.3 list
迭代器的基本操作
iterator begin(){
// link_type可以轉化為iterator(建構函式)
// iterator(過載了++ --等)
return (link_type)(node->next);
}
iterator begin()const{
return (link_type)(node->next);
}
iterator end(){
// 連結串列成環, 當指所以頭節點也就是end
return node;
}
iterator end()const{
return node;
}
empty判斷:
bool empty()const{return node == node->next;}
2.4 list
的插入操作
template<typename T>
typename SimpleList<T>::iterator SimpleList<T>::insert(
iterator position, const T& value){
link_type tmp = alloc_ctor_node(value);
// 調整雙向指標,使tmp插入進去
tmp->next = position.ptr;
tmp->prev = position.ptr->prev;
position.ptr->prev->next = tmp;
position.ptr->prev = tmp;
return tmp;
}
template<typename T>
void SimpleList<T>::push_back(const T& value){
insert(end(), value);
}
template<typename T>
typename SimpleList<T>::iterator SimpleList<T>::insert(
iterator position, size_t n, const T& value){
while(n--){
// 由於是相同的值,所以順序無關
insert(position, value);
}
}
接下來我們看 explicit SimpleList(size_t n);
建構函式
template<typename T>
void SimpleList<T>::fill_initialize(size_t n, const T& value){
// 先初始化起始點
empty_initialize();
insert(begin(), n, value);
}
template<typename T>
SimpleList<T>::SimpleList(size_type n, const T& value){
fill_initialize(n, value);
}
如下這個建構函式有點小問題,會建立一個臨時物件,然後呼叫物件的copy建構函式,實際上STL 中的list,只會呼叫物件的預設建構函式,這裡只是為了簡化,具體的可以見前面的vector原始碼實現分析文章。
template<typename T>
SimpleList<T>::SimpleList(size_t n){
fill_initialize(n, T());
}
3. 測試實現的基本的list
,包括基本型別如int
以及結構體。
3.1 基本型別int
測試
首先測試基本的int
SimpleList<int> slInt(5, 10);
std::cout<<slInt<<std::endl;
std::cout<<slInt.size()<<std::endl; // 8
輸出如下:
注意:
1. allocator分配的大小是以__list_node為大小單位,初始化的時空間配置器,沒有任何記憶體,由於申請的大小單位<128bytes,因此二級配置器,會給對應的free_list分配20個節點。
2. 建構函式根據大小n每次拿一個
接下來:
SimpleList<int> slInt1;
std::cout<<slInt1.size()<<std::endl; // 0
輸出如下:
會預設的為list構造一個頭節點。
3.2 結構體測試
結構體測試,結構體如下:
struct TestLst{
int a; char c1;
TestLst(int i = 0, char c = 'c'):a(i), c1(c){
std::cout<<"TestLst ctor a: "<<a<<" c1: "<<c1<<std::endl;
}
TestLst(const TestLst& tv):a(tv.a), c1(tv.c1){
std::cout<<"TestLst copy ctor a: "<<a<<" c1: "<<c1<<std::endl;
}
~TestLst(){
std::cout<<"TestLst dtor a: "<<a<<" c1: "<<c1<<std::endl;
}
};
測試程式碼如下:
SimpleList<TestLst> slStr(5);
std::cout<<"======now clear======"<<std::endl;
slStr.clear();
std::cout<<"======now insert new item======"<<std::endl;
slStr.push_back(TestLst());
輸出如下: