stl_list.h源碼剖析

容器list雙向環形鏈表

list相較於vector的連續線性空間,list顯得複雜許多,好處是每次插入或者刪除一個元素,就配置或釋放一個元素空間。因此list對於空間的運用絕對精準,一點也不浪費。而且對於任何位置的元素插入和元素移除,list永遠是常數時間<STL源碼剖析>

相關圖

在這裏插入圖片描述

節點設計
template <class T>
struct __list_node {
	typedef void* void_pointer;//缺陷,使用時都得強轉成_list_node類型
	void_pointer next;  // 指針指向下一個節點 
	void_pointer prev;  // 指針指向前一個節點
	T data;				//相應數據類型的data
};
__list_iterator
template<class T, class Ref, class Ptr>
struct __list_iterator { 
	typedef __list_iterator<T, T&, T*>             iterator;
	typedef __list_iterator<T, const T&, const T*> const_iterator;
	typedef __list_iterator<T, Ref, Ptr>           self;

	// 定義五種必要的迭代器類型
	typedef bidirectional_iterator_tag iterator_category;	 // (1) 雙向
	typedef T value_type; 			// (2) 數據類型
	typedef Ptr pointer; 			// (3) 指針類型
	typedef Ref reference; 			// (4) 引用
	typedef __list_node<T>* link_type; //節點指針類型
	typedef size_t size_type;
	typedef ptrdiff_t difference_type; // (5)

	link_type node;  // 指向容器的節點

	// 對迭代器解引用,獲取節點裏保存的data數據
	reference operator*() const { return (*node).data; }

	//重載前++運算符
	self& operator++() {
		//將當前節點指向下一個節點
		node = (link_type)((*node).next);
		return *this;
	}
	//重載後++運算符
	self operator++(int) {
		self tmp = *this;
		//當前節點++
		++*this;
		//將當前節點的賦給臨時變量並返回
		return tmp;
	}
	// 重載前--運算符
	self& operator--() {
		//將指針指向當前節點的上一個節點(pre)
		node = (link_type)((*node).prev);
		return *this;
	}
	//重載後--
	self operator--(int) {
		self tmp = *this;
		//前--
		--*this;
		//返回當前節點的臨時值
		return tmp;
	}
};
list容器
template <class T, class Alloc = alloc> //默認alloc
class list {
protected:
	typedef void* void_pointer;
	//節點
	typedef __list_node<T> list_node;
	//空間配置器,每次分配一個list_node節點大小的內存
	typedef simple_alloc<list_node, Alloc> list_node_allocator;
public:
	typedef T value_type;			//元素類型
	typedef value_type* pointer;	//指針類型
	typedef const value_type* const_pointer; //const指針類型
	typedef value_type& reference;			 //引用
	typedef const value_type& const_reference;
	typedef list_node* link_type;            //節點類型
	typedef size_t size_type;	
	typedef ptrdiff_t difference_type;

public:
	//迭代器
	//迭代器使用者,使用迭代器時,便會將迭代器中的節點指針指向容器
	typedef __list_iterator<T, T&, T*>             iterator;
	typedef __list_iterator<T, const T&, const T*> const_iterator;
protected:
	// 空間配置申請一個節點內存的大小,並返回指針
	link_type get_node() { return list_node_allocator::allocate(); }
	// 釋放內存
	void put_node(link_type p) { list_node_allocator::deallocate(p); }

	// 申請一個節點,並進行相應的賦值。insert時調用
	link_type create_node(const T& x) {
		link_type p = get_node();
		construct(&p->data, x);	//很重要調用place new構造函數;
		return p;
	}
	// 釋放一個節點 erase時調用
	void destroy_node(link_type p) {
		 //很重要調用析構函數 
		//inline void destroy(T* pointer) {
		//pointer->~T();	// 喚起 dtor ~T()
		destroy(&p->data); 	   
		put_node(p);		// 釋放內存給內存池
	}

protected:
	//雙向環形鏈表,永遠指向最後一個節點的下一個節點,以及第一個節點的上一個節點
	//空節點,哨兵節點
	//容器內唯一一個元素
	link_type node; 
	
	//容器的節點的初始化
	list() { empty_initialize(); }  
	void empty_initialize() {
		node = get_node();	// 申請一個節點
		node->next = node;	// 令頭尾都指向自己不設元素值
		node->prev = node;
	}
	//容器內保存的節點的下一個節點是第一個節點
	iterator begin() { return (link_type)((*node).next); }
	//end是尾節點的下一個節點,也就是容器內保存的節點
	iterator end() { return node; }
	
	//常見函數實現
	// 往頭結點前插入一個元素
	void push_front(const T& x) { insert(begin(), x); }
	// 往尾節點插入一個元素,end()之前也就是最後一個節點的後面
	void push_back(const T& x) { insert(end(), x); }
		
	// 移除頭結點
	void pop_front() { erase(begin()); }
	// 移除尾節點,容器節點是尾節點的下一個,所以移除(--tmp)
	void pop_back() {
		iterator tmp = end();
		erase(--tmp);
	}
	
	//向位置position之前插入一個元素
	iterator insert(iterator position, const T& x) {
		link_type tmp = create_node(x); // 申請一個節點,data數據爲x
		// 調整節點內的兩個指針(總共需要調整四個指針的指向,position的prev tmp的prev和next,position.prev的next)
		//tmp的next指向position
		tmp->next = position.node;
		//tmp的pre指針指向position的prev;
		tmp->prev = position.node->prev;
		//position上個節點的next指針指向tmp
		(link_type(position.node->prev))->next = tmp;
		//position的prev執行tmp
		position.node->prev = tmp;
		return tmp;
	}
	// 移除迭代器 position 所指節點
	iterator erase(iterator position) {
		link_type next_node = link_type(position.node->next);
		link_type prev_node = link_type(position.node->prev);
		//移除需要調整兩個指針(position上一個節點的next,以及position下一個節點的pre)
		prev_node->next = next_node;
		next_node->prev = prev_node;
		//移除節點
		destroy_node(position.node);
		//用移除了的節點的下一個節點初始化一個迭代器並返回
		return iterator(next_node);
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章