stl源码剖析list


前言`

list是数据结构中的双向链表,无需多言,懂的都懂!stl中的list封装了更多的功能,list相比vector,他的迭代器设计更符合一般认知。看看吧。


一、list的基础设计

list的元素在内存空间中是离散的,意味着我们不能简单地用指针来作为迭代器,因为指针进行++,–一类的操作时是在内存空间中顺序访问的,这满足不了list的需求,我们需要对迭代器进行专门设计。同样的,list里面的每个元素他所暗含的不仅仅是值,还有元素之间的关系,具体的一个例子就是list的每一个节点除了有自己的值只对外还应该包含他的上一个元素和下一个元素。
总之,看代码把

template <class T>
struct __list_node {
	typedef void* void_pointer;
	void_pointer prev;
	void_pointer next;
	T data;
|

template <class T, class Ref, class Ptr>
struct __list_iterator {
	//为什么要这么设计呢?
	//为iterator赋予iterator的作用是什么呢,懂了,一个字,图方便
	//但是为什么要把Ref和Ptr都加进去呢?
	//为了灵活设置?gpt给出的回答是这样的
	typedef __list_iterator<T, T&, T*>	iterator;
	typedef __list_iterator<T, Ref, Ptr> self;
	
	typedef bidirectional_iterator_tag	iterator_category;
	typedef T		value_type;
	typedef Ptr		pointer;
	typedef	Ref		reference;
	typedef __list_node<T>* link_type;
	typedef size_t	size_type;
	typedef ptrdiff_t	difference_type;

	link_type	node;

	__list_iterator(link_type x) : node(x) {}
	__list_iterator():node(nullptr){}
	//用一个另外的迭代器来初始化这一个迭代器
	__list_iterator(const iterator& x)node(x.node){}
	bool operator ==(const self& x)const {
		return node == x.node;
	}
	bool operator != (const self& x)const {
		return node != x.node;
	}

	//返回的是reference,所以对返回值操作能改变(*node)的data值
	reference operator*()const {return (*node).data}
	//返回的竟是指针所指内容的地址,为什么不返回node的地址呢?
	//我认为这里的设计不好
	pointer		operator->() const {return &(operator*());}

	self& operator++(){
		//注意我们在设计listnode的时候使用的是void*,因此这里需要进行一下改变
		node = (link_type)node->next;
		return *this;
	}

	self operator++(int){
		self temp = *this;
		++*this;
		return temp;
	}

	self& operator--(){
		node = (link_type)node->prev;
		return *this;
	}

	self operator--(int){
		self tmp = *this;
		--*this;
		return tmp;
	}
}

看了list的节点和迭代器的设计,接下来就是list这个整体的设计了

template <class T, class Alloc = alloc>
class list{
protected:
	typedef __list_node<T> 	list_node;
public:
	typedef list_node*		link_type;
protected:
	link_type node; 

iterator begin(){return (link_type)(node->next)}	
iterator end(){return node;}

bool empty(){
	return node == node->next;
}

size_type size() const{
	size_type result;
	distance(begin(), end(), result);
	return result;
}

reference front(){
	return *begin();
}
reference back(){
	return *(--end());
}
	
}

上述代码可以看出list作为一个容器,他对每一个节点进行了封装,并提供了相关的接口,例如得到list的头结点,尾结点之类的。隐藏在这背后的是list的构造与内存管理。

template <class T, class Alloc = alloc>
class list{
    typedef __list_node<T> list_node;
    typedef simple_alloc<list_node, Alloc> list_node_allocator;
protected:
    link_type   get_node(){
        return list_node_allocator::allocate();
    }

    void put_node(link_type posision){
        list_node_allocator::deallocate(position);
    }

    link_type create_node(const T& x){
        link_type pos = get_node();
        construct(&pos->data, x);//这里需要注意,通过给出一个值来构造的是node中的data,显然这里如果需要是要根据各种情况写出不同的重载方法
        return pos;
    }

    void destroy_node(link_type pos){
        destroy(&pos->data);//这里同样要注意destroy的依然是data那部分
        put_node(pos);
        return;
    }

public:
    list() {
        empty_initialize();
    }

    void push_back(const T& x){insert(end(), x);}

    iterator insert(iterator position, const T& value){
        link_type nodetmp = create_node(x);
        nodetmp->next = position;
        nodetmp->prev = position->prev;
        position->prev = nodetmp;
        nodetmp->prev->next = nodetmp;
        return nodetmp;
        //注意一下这里的转换方式
        //iterator的定义是__list_iterator<T, T&, T*> ,而他恰好有link_type的构造函数,通过隐式构造,完成转换
    }
    
    

private:
    void empty_initialize(){
        node = create_node();
        node->data = 0;
        node->next = node;
        node->prev = node;
        return ;
    }
}

如果看过了vector,那么这里的应该是没有什么新意的。destroy,construct,allocate,deallocate。不过值得注意的是,为什么侯捷把insert归类到内存管理这一小节。我们应该要清楚地看到insert函数里面是使用了内存管理相关的甘薯create_node,可能正因为如此作者这么归类。

二、list的元素操作

正如vector中有各种erase之类的对元素的操作,list中也有这些操作,这些操作的难点在于其算法。
看看吧

//头插,我们应该在begin之前插入
void push_front(const value_type& t){insert(begin(), t);}
void push_back(const value_type& t){insert(end(), t);}

//将position处的元素删除掉
iterator erase(iterator position){
	iterator tmp = position.node->next;
	position.node->prev->next = position.node->next;
	position.node->next->prev = position.node->prev;
	destroy_node(position.node);
	return tmp;
}

void pop_front(){
	erase(begin());
}

void pop_back(){
	iterator tmp = end();
	--tmp;
	erase(tmp);
}

template <class T, class Alloc>
void list<T, Alloc>::clear(){
	link_type cur = node->next;
	while(cur != node){
		link_type tmp = (link_type)cur->next;
		destroy(cur);
		cur = tmp;
	}
	node->next = node;
	node->prev = node;
}

template<class T, class Alloc>
void list<T, Alloc>::remove(const T& value){
	iterator first = begin();
	iterator last  = end();
	while(first != first){
		if(*first == value)
		iterator tmp = ++first;
		erase(first);
		first = tmp;
	}
}

void list<T, Alloc>::unique(){
	iterator first = begin();
	iterator last  = end();
	T tmp = *first;
	++first;
	while(first != last){
		if(tmp == *first){
			iterator next = ++first;
			erase(fisrt);
			first = next;
		}else{
			tmp = *fisrt;
			++first;
		}
	}
}

//只要思路正确,一定能写对!
void transfer(iterator position, iterator first, iterator last){
	if(position != last){
		first.node->prev->next = last.node;
		(link_type) node = last.node->prev;
		last.node->prev  = first.node->prev;
		first.node->prev = position.node->prev;
		last.node->prev->next = position.node;
		position.node->prev->next = first;
		position.node->prev = node;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内容简介回到顶部↑这本书不适合C++ 初学者,不适合 Genericity(泛型技术)初学者,或 STL 初学者。这本书也不适合带领你学习面向对象(Object Oriented)技术 — 是的,STL 与面向对象没有太多关连。本书前言清楚说明了书籍的定位和合适的读者,以及各类基础读物。如果你的Generic Programming/STL实力足以阅读本书所呈现的源码,那么,恭喜,你踏上了基度山岛,这儿有一座大宝库等着你。源码之前了无秘密,你将看到vector的实现、list的实现、heap的实现、deque的实现、RB-tree的实现、hash-table的实现、set/map 的实现;你将看到各种算法(排序、搜寻、排列组合、数据移动与复制…)的实现;你甚至将看到底层的memory pool 和高阶抽象的traits 机制的实现。那些数据结构、那些算法、那些重要观念、那些编程实务中最重要最根本的珍宝,那些蜇伏已久彷佛已经还给老师的记忆,将重新在你的脑中闪闪发光。 目录回到顶部↑庖丁解牛(侯捷自序) i 目录 v 前言 xvii 本书定位 xvii 合适的读者 xviii 最佳阅读方式 xviii 我所选择的剖析对象 xix 各章主题 xx 编译工具 xx 中英术语的运用风格 xxi 英文术语采用原则 xxii 版面字形风格 xxiii 源码形式与下载 xxiv 在线服务 xxvi 推荐读物 xxvi 第1章 STL 概论与版本简介001 1.1 STL 概论 001 1.1.1 STL的历史 003 1.1.2 STLC++ 标准程序库 003 . 1.2 STL 六大组件 - 功能与运用 004 1.3 GNU源码开放精神 007 1.4 HP STL实现版本 009 1.5 P.J. Plauger STL实现版本 010 1.6 Rouge Wave STL实现版本 011 1.7 STLport 实现版本 012 1.8 SGI STL实现版本 总览 013 1.8.1 GNU C++ header 文件分布 014 1.8.2 SGI STL 文件分布与简介 016 STL 标准头文件(无扩展名) 017 C++ 标准规格定案前,HP规范的STL头文件(扩展名 .h) 017 SGI STL 内部文件(SGI STL真正实现于此) 018 1.8.3 SGI STL 的组态设定(configuration) 019 1.9可能令你困惑的C++ 语法 026 1.9.1 stl_config.h 中的各种组态 027 组态3:static template member 027 组态5:class template partial specialization 028 组态6:function template partial order 028 组态7:explicit function template arguments 029 组态8:member templates 029 组态10:default template argument depend on previous template parameters 030 组态11:non-type template parameters 031 组态:bound friend template function 032 组态:class template explicit specialization 034 1.9.2 临时对象的产生与运用 036 1.9.3 静态常数整数成员在class 内部直接初始化 037 in-class static const integral data member initialization 1.9.4 increment/decrement/dereference 运算子 037 1.9.5 "前闭后开"区间表示法 [ ) 039 1.9.6 function call运算子(operator()) 040 第2章 空间配置器(allocator) 043 2.1 空间配置器的标准接口 043 2.1.1 设计一个简单的空间配置器,JJ::allocator 044 2.2 具备次配置力(sub-allocation)的SGI 空间配置器 047 2.2.1 SGI 标准的空间配置器,std::allocator 047 2.2.2 SGI 特殊的空间配置器,std::alloc 049 2.2.3 构造和析构基本工具:construct() 和 destroy() 051 2.2.4 空间的配置与释
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值