【STL源码学习】std::list类的类型别名分析

有了点模板元编程的traits基础,看STL源码清晰多了,以前看源码的时候总被各种各样的typedef给折腾得看不下去,

将<list>头文件的类继承结构简化如下

#include <xmemory>
#include <stdexcept>

#define _STD_BEGIN namespace std {
#define _STD_END }

_STD_BEGIN

// 第一个模板参数
template <class _Val_types>
class _List_val : public _Container_base { };

// 第二个模板参数
template <class _Ty, class _Alloc0>
struct _List_base_types { };

template <bool _Al_has_storage, class _Alloc_types>
class _List_alloc
	: public _List_val<typename _Alloc_types::_Val_types> { };

template <class _Ty, class _Alloc>  // 这里默认_Alloc不为空类型
class _List_buy     // !is_empty<_Alloc>::value暂不讨论
	: public _List_alloc<true, _List_base_types<_Ty, _Alloc>> { };

template <class _Ty, class _Alloc = allocator<_Ty> >
class list : public _List_buy<_Ty, _Alloc> { };

_STD_END

举个例子,看看list<int>这个实例化会产生什么效果,从下往上看。

_Ty被替换成int,_Alloc默认被替换成allocator<int>,上一层基类_List_buy的两个模板参数也是_Ty和_Alloc

再上一层基类_List_alloc有2个模板参数,第一个是bool值,编译期判断是否为空类型(empty class),第二个则是由_Ty和_Alloc两个模板参数实例化的_List_base_types类,该类没有基类型,这个类如同名字所说,list的基本类型。

_List_alloc的基类_List_val也是由_List_base_types作为模板参数实例化,_List_val的基类Container_base0仅仅包含两个函数体内为空的函数。

结论:list<>进行实例化后,模板参数_Ty是通过_List_base_types来定义list各类中的类型别名。

现在来看看_List_base_types内部的typedef

template<class _Ty,
	class _Alloc0>
	struct _List_base_types
	{	// types needed for a container base
	typedef _Alloc0 _Alloc;
	typedef _List_base_types<_Ty, _Alloc> _Myt;

	typedef _Wrap_alloc<_Alloc> _Alty0;
	typedef typename _Alty0::template rebind<_Ty>::other _Alty;

	typedef typename _Get_voidptr<_Alty, typename _Alty::pointer>::type
		_Voidptr;
	typedef _List_node<typename _Alty::value_type,
		_Voidptr> _Node;

	typedef typename _Alty::template rebind<_Node>::other _Alnod_type;
	typedef typename _Alnod_type::pointer _Nodeptr;
	typedef _Nodeptr& _Nodepref;

	typedef typename _If<_Is_simple_alloc<_Alty>::value,
		_List_simple_types<typename _Alty::value_type>,
		_List_iter_types<typename _Alty::value_type,
			typename _Alty::size_type,
			typename _Alty::difference_type,
			typename _Alty::pointer,
			typename _Alty::const_pointer,
			typename _Alty::reference,
			typename _Alty::const_reference,
			_Nodeptr> >::type
		_Val_types;
	};

_Myt为实例化后的该类模板的别名。

先看看最后的关键的_Val_types,变量类型,通过元函数(Meta Function)_If来完成类型计算。

template<bool,
	class _Ty1,
	class _Ty2>
	struct _If
	{	// type is _Ty2 for assumed false
	typedef _Ty2 type;
	};

template<class _Ty1,
	class _Ty2>
	struct _If<true, _Ty1, _Ty2>
	{	// type is _Ty1 for assumed true
	typedef _Ty1 type;
	};

通过模板特化来完成编译期的判断,三个模板参数,第一个为bool,如果第一个参数为true,那么类型type是_Ty1,否则类型type是_Ty2。

_Val_types第一个参数<_Is_simple_alloc<_Alty>::value,判断_Alty是否为“简单的内存分配器”,如果不是,则意味着你专门定制了特殊的内存分配器(类),并将这个类的类型别名(size_type、pointer等等)传递给_Val_types。

如果是,就直接用_List_simple_types,也就是list的简单类型。

template<class _Ty>
	struct _List_simple_types
		: public _Simple_types<_Ty>
	{	// wraps types needed by iterators
	typedef _List_node<_Ty, void *> _Node;
	typedef _Node *_Nodeptr;
	};

到这里就可以发现,链表类必须用到的结点类就在这里:_List_node<_Ty, void *>

template<class _Value_type,
	class _Voidptr>
	struct _List_node
		{	// list node
		_Voidptr _Next;	// successor node, or first element if head
		_Voidptr _Prev;	// predecessor node, or last element if head
		_Value_type _Myval;	// the stored value, unused if head

	private:
		_List_node& operator=(const _List_node&);
		};

template<class _Value_type>
	struct _List_node<_Value_type, void *>
		{	// list node
		typedef _List_node<_Value_type, void *> *_Nodeptr;
		_Nodeptr _Next;	// successor node, or first element if head
		_Nodeptr _Prev;	// predecessor node, or last element if head
		_Value_type _Myval;	// the stored value, unused if head

	private:
		_List_node& operator=(const _List_node&);
		};

结点类包含前向指针和后向指针,双向链表,并且把赋值运算符的重载置为private,禁止了结点间进行赋值。

因为进行赋值如果是简单的引用传递,没有意义,如果新建了个一模一样的结点,链表就不再是链表,而形成了闭合的图结构。

至于它的基类_Simple_types<_Ty>则是一些基本类型的集合

		// TEMPLATE CLASS _Simple_types
template<class _Value_type>
	struct _Simple_types
	{	// wraps types needed by iterators
	typedef _Value_type value_type;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	typedef value_type *pointer;
	typedef const value_type *const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	};

比如_Ty为int的话,_Simple_types里面的类型别名就是

int(值类型)、size_t(尺寸类型)、ptrdiff_t(差数类型)、int*(指针)、const int*(常指针)、int&(引用)、const int&(常饮用)

用了一些通用的接口来实现类型的统一。

时间: 2024-12-16 20:18:09

【STL源码学习】std::list类的类型别名分析的相关文章

【STL源码学习】STL算法学习之二

第一章:前言 学习笔记,记录学习STL算法的一些个人所得,在以后想用的时候可以快速拾起. 第二章:明细 copy 函数原型: template <class InputIterator, class OutputIterator> OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result); 函数作用: 将[first,last)区间的元素拷贝至result开头的迭代器区间,并返回赋值

【STL源码学习】细品vector

第一节:vector简介 vector是一种典型的类模板,使用的时候必须进行实例化. vector的数据存储在数组上,支持随机访问迭代器,支持下标操作[]和at操作,支持手动扩容和自动容量增长. vector是STL中的最常用容器,并支持STL的通用算法. 第二节:vector的迭代器介绍 vector支持iterator.const_iterator.reverse_iterator.const_reverse_iterator,前两个是正向迭代器,后两个是逆向迭代器. 迭代器支持操作:*操作

Mono源码学习笔记:Console类(四)

NullStream 类 (internal class) 以下就是 mcs/class/corlib/System.IO/NullStream.cs: 01: namespace System.IO 02: { 03: class NullStream : Stream 04: { 05: public override bool CanRead { get { return true; } } 06: public override bool CanSeek { get { return t

C++ STL源码学习之算法篇

///由于篇幅太长,因此,删去了很多接口,只分析了内部实现,算法对迭代器的要求也被删去 /// search. template <class _ForwardIter1, class _ForwardIter2> _ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1, _ForwardIter2 __first2, _ForwardIter2 __last2) { /// Test for empty range

C++ STL源码学习(list篇)

///STL list为双向循环链表 struct _List_node_base { _List_node_base* _M_next; _List_node_base* _M_prev; }; template <class _Tp> struct _List_node : public _List_node_base { _Tp _M_data; }; struct _List_iterator_base { typedef size_t size_type; typedef ptrdi

STL源码学习--vector使用方法总结

一.容器vector 使用vector必须包含头文件<vector>: #include<vector> 型别vector是一个定义于namespace std内的template: [cpp] view plaincopyprint? template<class _Ty, class _Ax = allocator<_Ty> > 第二个参数定义内存模型.我们一般采用默认的内存模型. 二.vector的功能 vector模塑出一个动态数组.vector将其

【STL源码学习】STL算法学习之三

第一章:前言 数量不多,用到的时候会很爽. 第二章:明细 STL算法中的又一个分类:分割:将已有元素按照既定规则分割成两部分.  is_partitioned 函数原型: template <class InputIterator, class UnaryPredicate> bool is_partitioned (InputIterator first, InputIterator last, UnaryPredicate pred); 函数作用: 如果序列被分为两部分,前一部分pred都

【STL源码学习】STL算法学习之一

第一章:引子 STL包含的算法头文件有三个:<algorithm><numeric><functional>,其中最大最常用的是<algorithm>,今天学习的是<algorithm>包含的算法中的第一部分:非修改顺序操作算法. 接下来学习的算法基于C++11标准,较老的IDE会支持不全面或者部分算法不支持. 第二章:原型解析 如分类名称体现的信息,本节的所有函数都不会修改序列,并且原理上都是顺序遍历迭代器实现的. all_of 函数原型: t

Mono源码学习笔记:Console类(三)

Buffer 类 (public static class) 以下就是 mcs/class/corlib/System/Buffer.cs: 001: // 002: // System.Buffer.cs 003: // 004: // Authors: 005: // Paolo Molaro ([email protected]) 006: // Dan Lewis ([email protected]) 007: // 008: // (C) 2001 Ximian, Inc. http