http://blog.csdn.net/xuqiqw/article/details/7676787
学习编程的人都知道,阅读、剖析名家代码乃是提高水平的捷径。源码之前,了无秘密,尤其是为了效率无所不用其极的SGI STL。大师们的缜密思维、经验结晶、技术思路、独到风格,都原原本本体现在源码之中。在你仔细推敲之中,迷惑不解之时,恍然大悟之际,你的经验、思维、视野、知识乃至技术品位都会获得快速的成长。
而作为一个喜欢追求事物内在原理、理论的人,这本书无疑很适合的。于是这本书在书柜、书架上躺了不知道多少个日子后,我拿起了他和另外一本《C++标准程序库》同时读了起来,虽然自从渡过C++语法学习过程后基本就没有用C++写过程序,基本上代码都是函数组成,对于MFC也是学习了原理就没碰过了(也许失去入口的用户代码让我有种失去掌控的感觉),但庖丁解牛说不定也只是为了一窥结构而已(也许...),嘛也就是学学原理罢。
在我写这篇文章的时候也就刚看完第3章,其中的一些观点不一定对。
首先是第2章空间配置器,一开始看标题的时候还以为是解释new操作符的实现,不过进去一看貌似还要底层点,根据STL规范空间配置器必须提供一些必要的接口,这些接口可以在书上看到就不说了。这个空间配置器对于各种容器是非常重要的,基本上STL中各种容器的内存分配就靠他了,比如说可以看到vector容器的参数vector<typenamt T,typename Alloc=alloc>,这是SGI STL中的vector,可以看到SGI STL vector第二个模版类型参数Alloc的默认配置器为alloc,其实各种STL实现版本的空间配置器有所不同,而标准应该是allocate,SGI STL采用这个非标准空间配置器主要就是为了效率,至于别的空间配置器大概都只是简单的包装了new delete全局操作符。
无论这个配置器的实现如何,SGI还为他再包装了一个接口如template<class T,class Alloc> class simple_alloc {....};,然后在具体的容器内部定义一个专门的内存分配型别,如typedef simple_alloc<T, alloc> data_allocate; 至此一个配置器就可以为容器所用。
而SGI空间配置器的具体实现分为2级配置实际分配工作采用C语言中最熟悉的malloc和free函数(效率考虑吧~),然后根据需要分配的字节数来具体实现不同规则的内存分配:当要求分配内存大于128字节时,直接malloc分配,仅仅加上一些错误处理,判断等这个空间配置器的一级配置就OK了。当要求的字节小于128时。。。。
嗯...上面的图是繁体的额额,理解应该没什么问题,就是STL会给你准备一个存有16个指针的数组,每个指针指向一组链起来的内存块,16个内存链链起来链条中每个块的大小分别为8,16,24,32,40,48,56,64,72,80,88,96,101,112,120,128,当用户需要小额内存时,就可以直接从链中取得空闲部分返回给用户使用,不够时还会从STL准备的内存池中取出内存进行链块的填充,一定程度上避免了内存碎片等灾难化的问题又提高了效率,更细节的可以看STL源码剖析。
感觉这已经可以看作是一个内存管理器了,啊哈哈.下面列出二级空间配置模版出来,使用空间配置时则根据需要使用不同配置器(代码均摘自SGI STL源码)
- template <int inst>
- class __malloc_alloc_template {
- private:
- static void *oom_malloc(size_t);
- static void *oom_realloc(void *, size_t);
- #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
- static void (* __malloc_alloc_oom_handler)();
- #endif
- public:
- static void * allocate(size_t n)
- {
- void *result = malloc(n);
- if (0 == result) result = oom_malloc(n);
- return result;
- }
- static void deallocate(void *p, size_t /* n */)
- {
- free(p);
- }
- static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
- {
- void * result = realloc(p, new_sz);
- if (0 == result) result = oom_realloc(p, new_sz);
- return result;
- }
- static void (* set_malloc_handler(void (*f)()))()
- {
- void (* old)() = __malloc_alloc_oom_handler;
- __malloc_alloc_oom_handler = f;
- return(old);
- }
- };
- typedef __malloc_alloc_template<0> malloc_alloc;
- template<class T, class Alloc>
- class simple_alloc {
- public:
- static T *allocate(size_t n)
- { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
- static T *allocate(void)
- { return (T*) Alloc::allocate(sizeof (T)); }
- static void deallocate(T *p, size_t n)
- { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
- static void deallocate(T *p)
- { Alloc::deallocate(p, sizeof (T)); }
- };
- template <bool threads, int inst>
- class __default_alloc_template {
- private:
- // Really we should use static const int x = N
- // instead of enum { x = N }, but few compilers accept the former.
- # ifndef __SUNPRO_CC
- enum {__ALIGN = 8};
- enum {__MAX_BYTES = 128};
- enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
- # endif
- static size_t ROUND_UP(size_t bytes) {
- return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
- }
- __PRIVATE:
- union obj {
- union obj * free_list_link;
- char client_data[1]; /* The client sees this. */
- };
- private:
- # ifdef __SUNPRO_CC
- static obj * __VOLATILE free_list[];
- // Specifying a size results in duplicate def for 4.1
- # else
- static obj * __VOLATILE free_list[__NFREELISTS];
- # endif
- static size_t FREELIST_INDEX(size_t bytes) {
- return (((bytes) + __ALIGN-1)/__ALIGN - 1);
- }
- // Returns an object of size n, and optionally adds to size n free list.
- static void *refill(size_t n);
- // Allocates a chunk for nobjs of size "size". nobjs may be reduced
- // if it is inconvenient to allocate the requested number.
- static char *chunk_alloc(size_t size, int &nobjs);
- // Chunk allocation state.
- static char *start_free;
- static char *end_free;
- static size_t heap_size;
- # ifdef __STL_SGI_THREADS
- static volatile unsigned long __node_allocator_lock;
- static void __lock(volatile unsigned long *);
- static inline void __unlock(volatile unsigned long *);
- # endif
- # ifdef __STL_PTHREADS
- static pthread_mutex_t __node_allocator_lock;
- # endif
- # ifdef __STL_WIN32THREADS
- static CRITICAL_SECTION __node_allocator_lock;
- static bool __node_allocator_lock_initialized;
- public:
- __default_alloc_template() {
- // This assumes the first constructor is called before threads
- // are started.
- if (!__node_allocator_lock_initialized) {
- InitializeCriticalSection(&__node_allocator_lock);
- __node_allocator_lock_initialized = true;
- }
- }
- private:
- # endif
- class lock {
- public:
- lock() { __NODE_ALLOCATOR_LOCK; }
- ~lock() { __NODE_ALLOCATOR_UNLOCK; }
- };
- friend class lock;
- public:
- /* n must be > 0 */
- static void * allocate(size_t n)
- {
- obj * __VOLATILE * my_free_list;
- obj * __RESTRICT result;
- if (n > (size_t) __MAX_BYTES) {
- return(malloc_alloc::allocate(n));
- }
- my_free_list = free_list + FREELIST_INDEX(n);
- // Acquire the lock here with a constructor call.
- // This ensures that it is released in exit or during stack
- // unwinding.
- # ifndef _NOTHREADS
- /*REFERENCED*/
- lock lock_instance;
- # endif
- result = *my_free_list;
- if (result == 0) {
- void *r = refill(ROUND_UP(n));
- return r;
- }
- *my_free_list = result -> free_list_link;
- return (result);
- };
- /* p may not be 0 */
- static void deallocate(void *p, size_t n)
- {
- obj *q = (obj *)p;
- obj * __VOLATILE * my_free_list;
- if (n > (size_t) __MAX_BYTES) {
- malloc_alloc::deallocate(p, n);
- return;
- }
- my_free_list = free_list + FREELIST_INDEX(n);
- // acquire lock
- # ifndef _NOTHREADS
- /*REFERENCED*/
- lock lock_instance;
- # endif /* _NOTHREADS */
- q -> free_list_link = *my_free_list;
- *my_free_list = q;
- // lock is released here
- }
- static void * reallocate(void *p, size_t old_sz, size_t new_sz);
- } ;
template <int inst>
class __malloc_alloc_template {
private:
static void *oom_malloc(size_t);
static void *oom_realloc(void *, size_t);
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
static void (* __malloc_alloc_oom_handler)();
#endif
public:
static void * allocate(size_t n)
{
void *result = malloc(n);
if (0 == result) result = oom_malloc(n);
return result;
}
static void deallocate(void *p, size_t /* n */)
{
free(p);
}
static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
void * result = realloc(p, new_sz);
if (0 == result) result = oom_realloc(p, new_sz);
return result;
}
static void (* set_malloc_handler(void (*f)()))()
{
void (* old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return(old);
}
};
typedef __malloc_alloc_template<0> malloc_alloc;
template<class T, class Alloc>
class simple_alloc {
public:
static T *allocate(size_t n)
{ return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
static T *allocate(void)
{ return (T*) Alloc::allocate(sizeof (T)); }
static void deallocate(T *p, size_t n)
{ if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
static void deallocate(T *p)
{ Alloc::deallocate(p, sizeof (T)); }
};
template <bool threads, int inst>
class __default_alloc_template {
private:
// Really we should use static const int x = N
// instead of enum { x = N }, but few compilers accept the former.
# ifndef __SUNPRO_CC
enum {__ALIGN = 8};
enum {__MAX_BYTES = 128};
enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
# endif
static size_t ROUND_UP(size_t bytes) {
return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
}
__PRIVATE:
union obj {
union obj * free_list_link;
char client_data[1]; /* The client sees this. */
};
private:
# ifdef __SUNPRO_CC
static obj * __VOLATILE free_list[];
// Specifying a size results in duplicate def for 4.1
# else
static obj * __VOLATILE free_list[__NFREELISTS];
# endif
static size_t FREELIST_INDEX(size_t bytes) {
return (((bytes) + __ALIGN-1)/__ALIGN - 1);
}
// Returns an object of size n, and optionally adds to size n free list.
static void *refill(size_t n);
// Allocates a chunk for nobjs of size "size". nobjs may be reduced
// if it is inconvenient to allocate the requested number.
static char *chunk_alloc(size_t size, int &nobjs);
// Chunk allocation state.
static char *start_free;
static char *end_free;
static size_t heap_size;
# ifdef __STL_SGI_THREADS
static volatile unsigned long __node_allocator_lock;
static void __lock(volatile unsigned long *);
static inline void __unlock(volatile unsigned long *);
# endif
# ifdef __STL_PTHREADS
static pthread_mutex_t __node_allocator_lock;
# endif
# ifdef __STL_WIN32THREADS
static CRITICAL_SECTION __node_allocator_lock;
static bool __node_allocator_lock_initialized;
public:
__default_alloc_template() {
// This assumes the first constructor is called before threads
// are started.
if (!__node_allocator_lock_initialized) {
InitializeCriticalSection(&__node_allocator_lock);
__node_allocator_lock_initialized = true;
}
}
private:
# endif
class lock {
public:
lock() { __NODE_ALLOCATOR_LOCK; }
~lock() { __NODE_ALLOCATOR_UNLOCK; }
};
friend class lock;
public:
/* n must be > 0 */
static void * allocate(size_t n)
{
obj * __VOLATILE * my_free_list;
obj * __RESTRICT result;
if (n > (size_t) __MAX_BYTES) {
return(malloc_alloc::allocate(n));
}
my_free_list = free_list + FREELIST_INDEX(n);
// Acquire the lock here with a constructor call.
// This ensures that it is released in exit or during stack
// unwinding.
# ifndef _NOTHREADS
/*REFERENCED*/
lock lock_instance;
# endif
result = *my_free_list;
if (result == 0) {
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result -> free_list_link;
return (result);
};
/* p may not be 0 */
static void deallocate(void *p, size_t n)
{
obj *q = (obj *)p;
obj * __VOLATILE * my_free_list;
if (n > (size_t) __MAX_BYTES) {
malloc_alloc::deallocate(p, n);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
// acquire lock
# ifndef _NOTHREADS
/*REFERENCED*/
lock lock_instance;
# endif /* _NOTHREADS */
q -> free_list_link = *my_free_list;
*my_free_list = q;
// lock is released here
}
static void * reallocate(void *p, size_t old_sz, size_t new_sz);
} ;
接下来是STL的迭代器,也可以说是智能指针(指针能够智能的实现我们一般指针需要的各种操作如遍历等,而我们不用关心他实际上如何去操作)。STL的中心思想在于,将数据容器和算法分开,彼此独立设计,最后再以一贴胶着剂将他们撮合在一起。而迭代器就是将他们黏在一起的胶水了。
而对于迭代器的实现,STL不单要达到效率的最佳化,还要达到泛化于各种算法之间游刃有余又要能作用于容器数据并不失效率,因此为了达到这种黏合剂的作用,当然的应运而生一些新的特性技术,例如"迭代器特性萃取机"iterator_traits,其定义如下
template <class I>
struct iterator_traits {
typedef typename I::iterator_category iterator_category; //萃取迭代器类型如单向迭代器,双向迭代器,随即迭代器等
typedef typename I::value_type value_type; //萃取迭代器所指对象的类型
typedef typename I::difference_type difference_type; //萃取2个迭代器之间的距离,用于一些算法
typedef typename I::pointer pointer; //萃取迭代器指针类型
typedef typename I::reference reference; //萃取迭代器引用类型
};
我就直接列出迭代器traits部分源代码好一窥轮廓(不包括各种特化版本)
- struct input_iterator_tag {};
- struct output_iterator_tag {};
- struct forward_iterator_tag : public input_iterator_tag {};
- struct bidirectional_iterator_tag : public forward_iterator_tag {};
- struct random_access_iterator_tag : public bidirectional_iterator_tag {};
- template <class T, class Distance> struct input_iterator {
- typedef input_iterator_tag iterator_category;
- typedef T value_type;
- typedef Distance difference_type;
- typedef T* pointer;
- typedef T& reference;
- };
- struct output_iterator {
- typedef output_iterator_tag iterator_category;
- typedef void value_type;
- typedef void difference_type;
- typedef void pointer;
- typedef void reference;
- };
- template <class T, class Distance> struct forward_iterator {
- typedef forward_iterator_tag iterator_category;
- typedef T value_type;
- typedef Distance difference_type;
- typedef T* pointer;
- typedef T& reference;
- };
- template <class T, class Distance> struct bidirectional_iterator {
- typedef bidirectional_iterator_tag iterator_category;
- typedef T value_type;
- typedef Distance difference_type;
- typedef T* pointer;
- typedef T& reference;
- };
- template <class T, class Distance> struct random_access_iterator {
- typedef random_access_iterator_tag iterator_category;
- typedef T value_type;
- typedef Distance difference_type;
- typedef T* pointer;
- typedef T& reference;
- };
- #ifdef __STL_USE_NAMESPACES
- template <class Category, class T, class Distance = ptrdiff_t,
- class Pointer = T*, class Reference = T&>
- struct iterator {
- typedef Category iterator_category;
- typedef T value_type;
- typedef Distance difference_type;
- typedef Pointer pointer;
- typedef Reference reference;
- };
- #endif /* __STL_USE_NAMESPACES */
- #ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
- template <class Iterator>
- struct iterator_traits {
- typedef typename Iterator::iterator_category iterator_category;
- typedef typename Iterator::value_type value_type;
- typedef typename Iterator::difference_type difference_type;
- typedef typename Iterator::pointer pointer;
- typedef typename Iterator::reference reference;
- };
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
template <class T, class Distance> struct input_iterator {
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
struct output_iterator {
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
};
template <class T, class Distance> struct forward_iterator {
typedef forward_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct bidirectional_iterator {
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T, class Distance> struct random_access_iterator {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
#ifdef __STL_USE_NAMESPACES
template <class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator {
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};
#endif /* __STL_USE_NAMESPACES */
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
template <class Iterator>
struct iterator_traits {
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
这一切都是为了效率而存在,许多STL算法都需要对迭代器进行步长操作,而对于一些可以直接+n进行步长跳跃的迭代器来说,单步慢慢增加就是效率上的损失了,所以typedef typename I::iterator_category iterator_category出现了,根据定义,这个类型指示应该是在每个容器中都有定义的并指示了相关迭代器的类型,而萃取机的工作就是提取出他的类型,那么怎么判断?如果只是单纯的利用条件判断来进行相关函数的选择,这样在运行期间进行的跳转同样会损失效率。那么怎么办?SGI STL提供了一种办法,精妙的是他不会有任何性能的损失,仅仅是定义了一些迭代器类型标识的标签,而且这些标签并不是常量!而是一些相互之间有继承关系的类,当然,没有任何成员-----他仅仅是个标签,如下所示:
// 五個做為標記用的型別(tag types)
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag : public input_iterator_tag { };
struct bidirectional_iterator_tag : public forward_iterator_tag { };
struct random_access_iterator_tag : public bidirectional_iterator_tag { };
为什么这样设计?在这不得不感叹SGI STL的设计人员设计的精妙-----------------因为用他可以激活C++的重载机制!当他作为一个参数的时候,所有的if else都可以抛开,不需要选择,不需要浪费效率,由编译器根据这个标签类型为你选择合适的实现版本,并且他们之间的继承关系也消除了单纯只做传递调用的函数,因为标签类会自动向上转型而调用所继承类版本的函数....
这种编程方法大量运用于STL实现品中,利用"内嵌类型"的编程技巧和编译器template参数推导功能增强C++未能提供的关于类型认证方面的能力。
因此SGI STL还有一个__type_traits私房菜,提供了一种机制,允许针对不同的类型属性,在编译时期完成函数派送决定-----是直接内存复制数据还是逐个构造类型,以达到效率的极致(STL中traits技术无处不在),下面列出性别萃取源代码(包括一些特化版本)。
- struct __true_type {
- };
- struct __false_type {
- };
- template <class type>
- struct __type_traits {
- typedef __true_type this_dummy_member_must_be_first;
- /* Do not remove this member. It informs a compiler which
- automatically specializes __type_traits that this
- __type_traits template is special. It just makes sure that
- things work if an implementation is using a template
- called __type_traits for something unrelated. */
- /* The following restrictions should be observed for the sake of
- compilers which automatically produce type specific specializations
- of this class:
- - You may reorder the members below if you wish
- - You may remove any of the members below if you wish
- - You must not rename members without making the corresponding
- name change in the compiler
- - Members you add will be treated like regular members unless
- you add the appropriate support in the compiler. */
- typedef __false_type has_trivial_default_constructor;
- typedef __false_type has_trivial_copy_constructor;
- typedef __false_type has_trivial_assignment_operator;
- typedef __false_type has_trivial_destructor;
- typedef __false_type is_POD_type;
- };
- // Provide some specializations. This is harmless for compilers that
- // have built-in __types_traits support, and essential for compilers
- // that don't.
- __STL_TEMPLATE_NULL struct __type_traits<char> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<signed char> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<unsigned char> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<short> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<unsigned short> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<int> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<unsigned int> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<long> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<unsigned long> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<float> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<double> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- __STL_TEMPLATE_NULL struct __type_traits<long double> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- #ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
- template <class T>
- struct __type_traits<T*> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- #else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
- struct __type_traits<char*> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- struct __type_traits<signed char*> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
- struct __type_traits<unsigned char*> {
- typedef __true_type has_trivial_default_constructor;
- typedef __true_type has_trivial_copy_constructor;
- typedef __true_type has_trivial_assignment_operator;
- typedef __true_type has_trivial_destructor;
- typedef __true_type is_POD_type;
- };
struct __true_type {
};
struct __false_type {
};
template <class type>
struct __type_traits {
typedef __true_type this_dummy_member_must_be_first;
/* Do not remove this member. It informs a compiler which
automatically specializes __type_traits that this
__type_traits template is special. It just makes sure that
things work if an implementation is using a template
called __type_traits for something unrelated. */
/* The following restrictions should be observed for the sake of
compilers which automatically produce type specific specializations
of this class:
- You may reorder the members below if you wish
- You may remove any of the members below if you wish
- You must not rename members without making the corresponding
name change in the compiler
- Members you add will be treated like regular members unless
you add the appropriate support in the compiler. */
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};
// Provide some specializations. This is harmless for compilers that
// have built-in __types_traits support, and essential for compilers
// that don't.
__STL_TEMPLATE_NULL struct __type_traits<char> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<signed char> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<unsigned char> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<short> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<unsigned short> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<int> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<unsigned int> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<long> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<unsigned long> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<float> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<double> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
__STL_TEMPLATE_NULL struct __type_traits<long double> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
template <class T>
struct __type_traits<T*> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
struct __type_traits<char*> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
struct __type_traits<signed char*> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
struct __type_traits<unsigned char*> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
在此感慨下STL软件框架,从前3章来看....完全没有看到任何一个函数的大小超过百行甚至50行,代码简单易懂,更多的是对于各种调用的封装以及隐藏,有些甚至一个函数中就是一个return ,真正隐藏在其中的更多更难理解的是一种框架的设计思路,一种思想在代码上的体现,代码虽少,内涵颇深。以前看MFC的时候也有种这种感觉,看起来许多短小简单的函数不是浪费效率有必要吗....现在看来更多的是一种设计思想上的体现,并不是代码越多,一个函数越复杂就好。
而能从如此庞大复杂的源代码中提取剖析这种设计思路并呈现给读者,侯先生堪执牛耳!
SGI STL的容器实现(traits技术广泛用于容器中和迭代器中)
ps:篇幅原因代码经过删减并非完整代码
1)vector容器
vector容器可以想象成一个动态数组,对于空间足够的情况,行为类似数组但更加安全,当空间不足时,vector容器会自动实现 "配置新空间/数据移动/释放旧空间" 的行为,vector容器的空间配置器默认使用的是上次讲到的alloc配置器,迭代器其实就是指针,嗯...除了要加上一些traits技术用到的型别定义整个实现还是比较简单的
- template <class T, class Alloc = alloc>
- class vector {
- public:
- typedef T value_type;
- typedef value_type* pointer;
- typedef const value_type* const_pointer;
- typedef value_type* iterator;
- typedef const value_type* const_iterator;
- typedef value_type& reference;
- typedef const value_type& const_reference;
- typedef size_t size_type;
- typedef ptrdiff_t difference_type;
- protected:
- typedef simple_alloc<value_type, Alloc> data_allocator;
- iterator start;
- iterator finish;
- iterator end_of_storage;
- void insert_aux(iterator position, const T& x);
- void deallocate() {
- if (start) data_allocator::deallocate(start, end_of_storage - start);
- }
- void fill_initialize(size_type n, const T& value) {
- start = allocate_and_fill(n, value);
- finish = start + n;
- end_of_storage = finish;
- }
- public:
- iterator begin() { return start; }
- const_iterator begin() const { return start; }
- iterator end() { return finish; }
- const_iterator end() const { return finish; }
- size_type size() const { return size_type(end() - begin()); }
- size_type max_size() const { return size_type(-1) / sizeof(T); }
- size_type capacity() const { return size_type(end_of_storage - begin()); }
- bool empty() const { return begin() == end(); }
- reference operator[](size_type n) { return *(begin() + n); }
- const_reference operator[](size_type n) const { return *(begin() + n); }
- vector() : start(0), finish(0), end_of_storage(0) {}
- vector(size_type n, const T& value) { fill_initialize(n, value); }
- vector(int n, const T& value) { fill_initialize(n, value); }
- vector(long n, const T& value) { fill_initialize(n, value); }
- explicit vector(size_type n) { fill_initialize(n, T()); }
- vector(const vector<T, Alloc>& x) {
- start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
- finish = start + (x.end() - x.begin());
- end_of_storage = finish;
- }
- ~vector() {
- destroy(start, finish);
- deallocate();
- }
- vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
- reference front() { return *begin(); }
- const_reference front() const { return *begin(); }
- reference back() { return *(end() - 1); }
- const_reference back() const { return *(end() - 1); }
- void push_back(const T& x) {
- if (finish != end_of_storage) {
- construct(finish, x);
- ++finish;
- }
- else
- insert_aux(end(), x);
- }
- iterator insert(iterator position) { return insert(position, T()); }
- void insert (iterator pos, size_type n, const T& x);
- void pop_back() {
- --finish;
- destroy(finish);
- }
- iterator erase(iterator position) {
- if (position + 1 != end())
- copy(position + 1, finish, position);
- --finish;
- destroy(finish);
- return position;
- }
- void resize(size_type new_size, const T& x) {
- if (new_size < size())
- erase(begin() + new_size, end());
- else
- insert(end(), new_size - size(), x);
- }
- void resize(size_type new_size) { resize(new_size, T()); }
- void clear() { erase(begin(), end()); }
- protected:
- iterator allocate_and_fill(size_type n, const T& x) {
- iterator result = data_allocator::allocate(n);
- __STL_TRY {
- uninitialized_fill_n(result, n, x);
- return result;
- }
- __STL_UNWIND(data_allocator::deallocate(result, n));
- }
- };
template <class T, class Alloc = alloc>
class vector {
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
protected:
typedef simple_alloc<value_type, Alloc> data_allocator;
iterator start;
iterator finish;
iterator end_of_storage;
void insert_aux(iterator position, const T& x);
void deallocate() {
if (start) data_allocator::deallocate(start, end_of_storage - start);
}
void fill_initialize(size_type n, const T& value) {
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}
public:
iterator begin() { return start; }
const_iterator begin() const { return start; }
iterator end() { return finish; }
const_iterator end() const { return finish; }
size_type size() const { return size_type(end() - begin()); }
size_type max_size() const { return size_type(-1) / sizeof(T); }
size_type capacity() const { return size_type(end_of_storage - begin()); }
bool empty() const { return begin() == end(); }
reference operator[](size_type n) { return *(begin() + n); }
const_reference operator[](size_type n) const { return *(begin() + n); }
vector() : start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T& value) { fill_initialize(n, value); }
vector(int n, const T& value) { fill_initialize(n, value); }
vector(long n, const T& value) { fill_initialize(n, value); }
explicit vector(size_type n) { fill_initialize(n, T()); }
vector(const vector<T, Alloc>& x) {
start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
finish = start + (x.end() - x.begin());
end_of_storage = finish;
}
~vector() {
destroy(start, finish);
deallocate();
}
vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
void push_back(const T& x) {
if (finish != end_of_storage) {
construct(finish, x);
++finish;
}
else
insert_aux(end(), x);
}
iterator insert(iterator position) { return insert(position, T()); }
void insert (iterator pos, size_type n, const T& x);
void pop_back() {
--finish;
destroy(finish);
}
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position);
--finish;
destroy(finish);
return position;
}
void resize(size_type new_size, const T& x) {
if (new_size < size())
erase(begin() + new_size, end());
else
insert(end(), new_size - size(), x);
}
void resize(size_type new_size) { resize(new_size, T()); }
void clear() { erase(begin(), end()); }
protected:
iterator allocate_and_fill(size_type n, const T& x) {
iterator result = data_allocator::allocate(n);
__STL_TRY {
uninitialized_fill_n(result, n, x);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
};
大概定义也就这样,为了简便删了许多操作
2)list容器
list的底层实现其实就是个双向循环链表,并且只需要一个节点成员就够了(一个空的节点本身作为end(),end().next其实就是begin(),很多容器都是这么干的用一个空节点来简化操作在很多容器用到了,同时也是C++容器弥漫各处的半开闭区间的最好表现),空间配置器缺省也为那个alloc,节点结构就跟你要写一个双向循环链表的定义一样,但是为了获得类似迭代器的行为以适应各种操作、算法达到泛化的效果,list配备了一个自己专门的迭代器来包装list节点指针,其中list节点即为其数据成员,然后重载各种操作符达到模拟指针的各种操作,而实际的定义如下
- template <class T, class Alloc = alloc>
- class list {
- protected:
- typedef void* void_pointer;
- typedef __list_node<T> 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;
- 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); }
- link_type create_node(const T& x) {
- link_type p = get_node();
- __STL_TRY {
- construct(&p->data, x);
- }
- __STL_UNWIND(put_node(p));
- return p;
- }
- void destroy_node(link_type p) {
- destroy(&p->data);
- put_node(p);
- }
- protected:
- void empty_initialize() {
- node = get_node();
- node->next = node;
- node->prev = node;
- }
- void fill_initialize(size_type n, const T& value) {
- empty_initialize();
- __STL_TRY {
- insert(begin(), n, value);
- }
- __STL_UNWIND(clear(); put_node(node));
- }
- protected:
- link_type node;
- public:
- list() { empty_initialize(); }
- iterator begin() { return (link_type)((*node).next); }
- const_iterator begin() const { return (link_type)((*node).next); }
- iterator end() { return node; }
- const_iterator end() const { return node; }
- bool empty() const { return node->next == node; }
- size_type size() const {
- size_type result = 0;
- distance(begin(), end(), result);
- return result;
- }
- size_type max_size() const { return size_type(-1); }
- reference front() { return *begin(); }
- const_reference front() const { return *begin(); }
- reference back() { return *(--end()); }
- const_reference back() const { return *(--end()); }
- void swap(list<T, Alloc>& x) { __STD::swap(node, x.node); }
- iterator insert(iterator position, const T& x) {
- link_type tmp = create_node(x);
- tmp->next = position.node;
- tmp->prev = position.node->prev;
- (link_type(position.node->prev))->next = tmp;
- position.node->prev = tmp;
- return tmp;
- }
- iterator insert(iterator position) { return insert(position, T()); }
- void insert(iterator pos, size_type n, const T& x);
- void insert(iterator pos, int n, const T& x) {
- insert(pos, (size_type)n, x);
- }
- void insert(iterator pos, long n, const T& x) {
- insert(pos, (size_type)n, x);
- }
- void push_front(const T& x) { insert(begin(), x); }
- void push_back(const T& x) { insert(end(), x); }
- iterator erase(iterator position) {
- link_type next_node = link_type(position.node->next);
- link_type prev_node = link_type(position.node->prev);
- prev_node->next = next_node;
- next_node->prev = prev_node;
- destroy_node(position.node);
- return iterator(next_node);
- }
- iterator erase(iterator first, iterator last);
- void resize(size_type new_size, const T& x);
- void resize(size_type new_size) { resize(new_size, T()); }
- void clear();
- void pop_front() { erase(begin()); }
- void pop_back() {
- iterator tmp = end();
- erase(--tmp);
- }
- list(size_type n, const T& value) { fill_initialize(n, value); }
- list(int n, const T& value) { fill_initialize(n, value); }
- list(long n, const T& value) { fill_initialize(n, value); }
- explicit list(size_type n) { fill_initialize(n, T()); }
- list(const list<T, Alloc>& x) {
- range_initialize(x.begin(), x.end());
- }
- ~list() {
- clear();
- put_node(node);
- }
- list<T, Alloc>& operator=(const list<T, Alloc>& x);
- protected:
- void transfer(iterator position, iterator first, iterator last) {
- if (position != last) {
- (*(link_type((*last.node).prev))).next = position.node;
- (*(link_type((*first.node).prev))).next = last.node;
- (*(link_type((*position.node).prev))).next = first.node;
- link_type tmp = link_type((*position.node).prev);
- (*position.node).prev = (*last.node).prev;
- (*last.node).prev = (*first.node).prev;
- (*first.node).prev = tmp;
- }
- }
- public:
- void splice(iterator position, list& x) {
- if (!x.empty())
- transfer(position, x.begin(), x.end());
- }
- void remove(const T& value);
- void unique();
- void merge(list& x);
- void reverse();
- void sort();
- friend bool operator== __STL_NULL_TMPL_ARGS (const list& x, const list& y);
- };
template <class T, class Alloc = alloc>
class list {
protected:
typedef void* void_pointer;
typedef __list_node<T> 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;
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); }
link_type create_node(const T& x) {
link_type p = get_node();
__STL_TRY {
construct(&p->data, x);
}
__STL_UNWIND(put_node(p));
return p;
}
void destroy_node(link_type p) {
destroy(&p->data);
put_node(p);
}
protected:
void empty_initialize() {
node = get_node();
node->next = node;
node->prev = node;
}
void fill_initialize(size_type n, const T& value) {
empty_initialize();
__STL_TRY {
insert(begin(), n, value);
}
__STL_UNWIND(clear(); put_node(node));
}
protected:
link_type node;
public:
list() { empty_initialize(); }
iterator begin() { return (link_type)((*node).next); }
const_iterator begin() const { return (link_type)((*node).next); }
iterator end() { return node; }
const_iterator end() const { return node; }
bool empty() const { return node->next == node; }
size_type size() const {
size_type result = 0;
distance(begin(), end(), result);
return result;
}
size_type max_size() const { return size_type(-1); }
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(--end()); }
const_reference back() const { return *(--end()); }
void swap(list<T, Alloc>& x) { __STD::swap(node, x.node); }
iterator insert(iterator position, const T& x) {
link_type tmp = create_node(x);
tmp->next = position.node;
tmp->prev = position.node->prev;
(link_type(position.node->prev))->next = tmp;
position.node->prev = tmp;
return tmp;
}
iterator insert(iterator position) { return insert(position, T()); }
void insert(iterator pos, size_type n, const T& x);
void insert(iterator pos, int n, const T& x) {
insert(pos, (size_type)n, x);
}
void insert(iterator pos, long n, const T& x) {
insert(pos, (size_type)n, x);
}
void push_front(const T& x) { insert(begin(), x); }
void push_back(const T& x) { insert(end(), x); }
iterator erase(iterator position) {
link_type next_node = link_type(position.node->next);
link_type prev_node = link_type(position.node->prev);
prev_node->next = next_node;
next_node->prev = prev_node;
destroy_node(position.node);
return iterator(next_node);
}
iterator erase(iterator first, iterator last);
void resize(size_type new_size, const T& x);
void resize(size_type new_size) { resize(new_size, T()); }
void clear();
void pop_front() { erase(begin()); }
void pop_back() {
iterator tmp = end();
erase(--tmp);
}
list(size_type n, const T& value) { fill_initialize(n, value); }
list(int n, const T& value) { fill_initialize(n, value); }
list(long n, const T& value) { fill_initialize(n, value); }
explicit list(size_type n) { fill_initialize(n, T()); }
list(const list<T, Alloc>& x) {
range_initialize(x.begin(), x.end());
}
~list() {
clear();
put_node(node);
}
list<T, Alloc>& operator=(const list<T, Alloc>& x);
protected:
void transfer(iterator position, iterator first, iterator last) {
if (position != last) {
(*(link_type((*last.node).prev))).next = position.node;
(*(link_type((*first.node).prev))).next = last.node;
(*(link_type((*position.node).prev))).next = first.node;
link_type tmp = link_type((*position.node).prev);
(*position.node).prev = (*last.node).prev;
(*last.node).prev = (*first.node).prev;
(*first.node).prev = tmp;
}
}
public:
void splice(iterator position, list& x) {
if (!x.empty())
transfer(position, x.begin(), x.end());
}
void remove(const T& value);
void unique();
void merge(list& x);
void reverse();
void sort();
friend bool operator== __STL_NULL_TMPL_ARGS (const list& x, const list& y);
};
可以看到list中数据成员直接就是list的节点而不是经过包装后的迭代器,而且后面容器基本都是这么干,大概可以想象STL的设计者需要的并不是迭代器与容器之间的一种包含关系(如果是我的话我肯定这么干,直接包装节点,再把节点包装成迭代器,再把迭代器包装进对应的容器(层层包装这就是我对面向对象的认识了...看来没那么简单)。对于这种设计思路我反正是不懂为什么,能带来什么好处.....
按我自己的理解,就是让迭代器起到一个胶水的作用-----具体的容器实现相关的操作什么的,而STL的算法提供的就是一个迭代器接口,为了将2者既数据与算法粘合在一起,迭代器就产生了,他是一个独立于数据与算法的泛化类型而又连接起数据与算法,而容器为了产生迭代器,只要对自己的迭代器进行声明,当用户需要迭代器的时候容器只需要返回相关节点让迭代器以这个节点生成对应的迭代器并反馈给用户,而对于节点的操作由具体迭代器内部管理,算法因此得以行进。
以前一直认为迭代器只是在容器内对于指针的包装,现在看来,迭代器只是一个抽象,不属于任何谁,算法和数据(容器)是2个独立的板块,迭代器就是一个桥架起了算法与数据,让他们协同并高效运作。
ps:其实还有个不在C++标准内但SGI STL提供了的容器名为slist,slist和list的差别在于slist的迭代器是个前向迭代器而list的迭代器属于双向迭代器,并且slist的架构比list的架构复杂的多,slist本身是个单向链表,并且也准备了一个空节点以省去一些特殊情况操作,在这里是一个头结点。
3)deque容器极其配接器
对于deque容器,其内部实现也是线性的,但是deque容器是以动态地分段连续空间组合而成,随时可以增加一段新的空间并连接起来,而且元素的存储都是经过计算尽量放在中间段空间的,所以如果说vector最大的弊端就是对于头部元素的删除耗费大量时间以及空间,那么deque最擅长的就是头尾元素的操作,而且不会发生vector中由于空间不足而产生的内存重新分配,数据复制,释放旧空间的情况了.....嗯,也就是个双端队列了
不过deque因为他的结构,他的迭代器就不是普通的指针了,运算需要涉及跳跃段等操作,排序等操作因此就更复杂了,所以选用哪种容器需要斟酌。
实现中deque会负责维护一个指针数组,在STL源码剖析中叫中控器,数组中每个指针只想一个存储真正数据的缓冲区。
由于其特别的存储结构,deque容器内就需要2个空间配置器,一个是对于中控器也就是那个指针数组,还有一个就是常见的负责对元素的配置了,然后为了维护其结构的完整性,在插入删除元素等操作中都要进行情况测试以及可能的空间配置,所以对于大量的元素移动操作效率可想而知,下面附上定义
ps:看了下,迭代器在deque中就直接作为成员了...于是就有点搞不懂了
- template <class T, class Alloc = alloc, size_t BufSiz = 0>
- class deque {
- public: // Basic types
- typedef T value_type;
- typedef value_type* pointer;
- typedef const value_type* const_pointer;
- typedef value_type& reference;
- typedef const value_type& const_reference;
- typedef size_t size_type;
- typedef ptrdiff_t difference_type;
- public: // Iterators
- //…
- protected: // Internal typedefs
- typedef pointer* map_pointer;
- typedef simple_alloc<value_type, Alloc> data_allocator;
- typedef simple_alloc<pointer, Alloc> map_allocator;
- static size_type buffer_size() {
- return __deque_buf_size(BufSiz, sizeof(value_type));
- }
- static size_type initial_map_size() { return 8; }
- protected: // Data members
- iterator start;
- iterator finish;
- map_pointer map;
- size_type map_size;
- public: // Basic accessors
- iterator begin() { return start; }
- iterator end() { return finish; }
- const_iterator begin() const { return start; }
- const_iterator end() const { return finish; }
- reverse_iterator rbegin() { return reverse_iterator(finish); }
- reverse_iterator rend() { return reverse_iterator(start); }
- const_reverse_iterator rbegin() const {
- return const_reverse_iterator(finish);
- }
- const_reverse_iterator rend() const {
- return const_reverse_iterator(start);
- }
- reference operator[](size_type n) { return start[difference_type(n)]; }
- const_reference operator[](size_type n) const {
- return start[difference_type(n)];
- }
- reference front() { return *start; }
- reference back() {
- iterator tmp = finish;
- --tmp;
- return *tmp;
- }
- const_reference front() const { return *start; }
- const_reference back() const {
- const_iterator tmp = finish;
- --tmp;
- return *tmp;
- }
- size_type size() const { return finish - start;; }
- size_type max_size() const { return size_type(-1); }
- bool empty() const { return finish == start; }
- public: // Constructor, destructor.
- deque()
- : start(), finish(), map(0), map_size(0)
- {
- create_map_and_nodes(0);
- }
- deque(const deque& x)
- : start(), finish(), map(0), map_size(0)
- {
- create_map_and_nodes(x.size());
- __STL_TRY {
- uninitialized_copy(x.begin(), x.end(), start);
- }
- __STL_UNWIND(destroy_map_and_nodes());
- }
- deque(size_type n, const value_type& value)
- : start(), finish(), map(0), map_size(0)
- {
- fill_initialize(n, value);
- }
- explicit deque(size_type n)
- : start(), finish(), map(0), map_size(0)
- {
- fill_initialize(n, value_type());
- }
- ~deque() {
- destroy(start, finish);
- destroy_map_and_nodes();
- }
- deque& operator= (const deque& x) {
- const size_type len = size();
- if (&x != this) {
- if (len >= x.size())
- erase(copy(x.begin(), x.end(), start), finish);
- else {
- const_iterator mid = x.begin() + difference_type(len);
- copy(x.begin(), mid, start);
- insert(finish, mid, x.end());
- }
- }
- return *this;
- }
- public: // push_* and pop_*
- //..
- public: // Insert
- iterator insert(iterator position, const value_type& x) {
- if (position.cur == start.cur) {
- push_front(x);
- return start;
- }
- else if (position.cur == finish.cur) {
- push_back(x);
- iterator tmp = finish;
- --tmp;
- return tmp;
- }
- else {
- return insert_aux(position, x);
- }
- }
- iterator insert(iterator position) { return insert(position, value_type()); }
- void insert(iterator pos, size_type n, const value_type& x);
- void insert(iterator pos, int n, const value_type& x) {
- insert(pos, (size_type) n, x);
- }
- void insert(iterator pos, long n, const value_type& x) {
- insert(pos, (size_type) n, x);
- }
- void resize(size_type new_size, const value_type& x) {
- const size_type len = size();
- if (new_size < len)
- erase(start + new_size, finish);
- else
- insert(finish, new_size - len, x);
- }
- void resize(size_type new_size) { resize(new_size, value_type()); }
- public: // Erase
- iterator erase(iterator pos) {
- iterator next = pos;
- ++next;
- difference_type index = pos - start;
- if (index < (size() >> 1)) {
- copy_backward(start, pos, next);
- pop_front();
- }
- else {
- copy(next, finish, pos);
- pop_back();
- }
- return start + index;
- }
- iterator erase(iterator first, iterator last);
- void clear();
- protected: // Internal construction/destruction
- void create_map_and_nodes(size_type num_elements);
- void destroy_map_and_nodes();
- void fill_initialize(size_type n, const value_type& value);
- protected: // Internal push_* and pop_*
- void push_back_aux(const value_type& t);
- void push_front_aux(const value_type& t);
- void pop_back_aux();
- void pop_front_aux();
- protected: // Internal insert functions
- iterator insert_aux(iterator pos, const value_type& x);
- void insert_aux(iterator pos, size_type n, const value_type& x);
- void new_elements_at_front(size_type new_elements);
- void new_elements_at_back(size_type new_elements);
- void destroy_nodes_at_front(iterator before_start);
- void destroy_nodes_at_back(iterator after_finish);
- protected: // Allocation of map and nodes
- // Makes sure the map has space for new nodes. Does not actually
- // add the nodes. Can invalidate map pointers. (And consequently,
- // deque iterators.)
- void reallocate_map(size_type nodes_to_add, bool add_at_front);
- pointer allocate_node() { return data_allocator::allocate(buffer_size()); }
- void deallocate_node(pointer n) {
- data_allocator::deallocate(n, buffer_size());
- }
- };
template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque {
public: // Basic types
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
public: // Iterators
//…
protected: // Internal typedefs
typedef pointer* map_pointer;
typedef simple_alloc<value_type, Alloc> data_allocator;
typedef simple_alloc<pointer, Alloc> map_allocator;
static size_type buffer_size() {
return __deque_buf_size(BufSiz, sizeof(value_type));
}
static size_type initial_map_size() { return 8; }
protected: // Data members
iterator start;
iterator finish;
map_pointer map;
size_type map_size;
public: // Basic accessors
iterator begin() { return start; }
iterator end() { return finish; }
const_iterator begin() const { return start; }
const_iterator end() const { return finish; }
reverse_iterator rbegin() { return reverse_iterator(finish); }
reverse_iterator rend() { return reverse_iterator(start); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(finish);
}
const_reverse_iterator rend() const {
return const_reverse_iterator(start);
}
reference operator[](size_type n) { return start[difference_type(n)]; }
const_reference operator[](size_type n) const {
return start[difference_type(n)];
}
reference front() { return *start; }
reference back() {
iterator tmp = finish;
--tmp;
return *tmp;
}
const_reference front() const { return *start; }
const_reference back() const {
const_iterator tmp = finish;
--tmp;
return *tmp;
}
size_type size() const { return finish - start;; }
size_type max_size() const { return size_type(-1); }
bool empty() const { return finish == start; }
public: // Constructor, destructor.
deque()
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(0);
}
deque(const deque& x)
: start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(x.size());
__STL_TRY {
uninitialized_copy(x.begin(), x.end(), start);
}
__STL_UNWIND(destroy_map_and_nodes());
}
deque(size_type n, const value_type& value)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value);
}
explicit deque(size_type n)
: start(), finish(), map(0), map_size(0)
{
fill_initialize(n, value_type());
}
~deque() {
destroy(start, finish);
destroy_map_and_nodes();
}
deque& operator= (const deque& x) {
const size_type len = size();
if (&x != this) {
if (len >= x.size())
erase(copy(x.begin(), x.end(), start), finish);
else {
const_iterator mid = x.begin() + difference_type(len);
copy(x.begin(), mid, start);
insert(finish, mid, x.end());
}
}
return *this;
}
public: // push_* and pop_*
//..
public: // Insert
iterator insert(iterator position, const value_type& x) {
if (position.cur == start.cur) {
push_front(x);
return start;
}
else if (position.cur == finish.cur) {
push_back(x);
iterator tmp = finish;
--tmp;
return tmp;
}
else {
return insert_aux(position, x);
}
}
iterator insert(iterator position) { return insert(position, value_type()); }
void insert(iterator pos, size_type n, const value_type& x);
void insert(iterator pos, int n, const value_type& x) {
insert(pos, (size_type) n, x);
}
void insert(iterator pos, long n, const value_type& x) {
insert(pos, (size_type) n, x);
}
void resize(size_type new_size, const value_type& x) {
const size_type len = size();
if (new_size < len)
erase(start + new_size, finish);
else
insert(finish, new_size - len, x);
}
void resize(size_type new_size) { resize(new_size, value_type()); }
public: // Erase
iterator erase(iterator pos) {
iterator next = pos;
++next;
difference_type index = pos - start;
if (index < (size() >> 1)) {
copy_backward(start, pos, next);
pop_front();
}
else {
copy(next, finish, pos);
pop_back();
}
return start + index;
}
iterator erase(iterator first, iterator last);
void clear();
protected: // Internal construction/destruction
void create_map_and_nodes(size_type num_elements);
void destroy_map_and_nodes();
void fill_initialize(size_type n, const value_type& value);
protected: // Internal push_* and pop_*
void push_back_aux(const value_type& t);
void push_front_aux(const value_type& t);
void pop_back_aux();
void pop_front_aux();
protected: // Internal insert functions
iterator insert_aux(iterator pos, const value_type& x);
void insert_aux(iterator pos, size_type n, const value_type& x);
void new_elements_at_front(size_type new_elements);
void new_elements_at_back(size_type new_elements);
void destroy_nodes_at_front(iterator before_start);
void destroy_nodes_at_back(iterator after_finish);
protected: // Allocation of map and nodes
// Makes sure the map has space for new nodes. Does not actually
// add the nodes. Can invalidate map pointers. (And consequently,
// deque iterators.)
void reallocate_map(size_type nodes_to_add, bool add_at_front);
pointer allocate_node() { return data_allocator::allocate(buffer_size()); }
void deallocate_node(pointer n) {
data_allocator::deallocate(n, buffer_size());
}
};
然后是deque的配接器stack和queue了,有了deque这2个东西就很好搞了,只要将deque作为其成员然后只提供一些操作就能模拟出这2种数据结构了
4)priority_queue容器
其实就是个优先级队列,底层是一个heap结构,由于heap结构的原因,他并不提供迭代器,而priority_queue只需将heap作为成员,提供一些转调用操作即可实现priority_queue容器,代码就不上了
5)set,map等关联容器
这几个关联容器底层都是以红黑树实现,至于具体的相关红黑树实现可以到STL源码剖析或者数据结构方面的书上找,并且STL中实现提供了一个比根节点还要高一点的头结点来实现一些技巧并避免一些特殊情况的处理,他的迭代器结构也比较复杂...下面直接上个set的定义吧
- template <class Key, class Compare = less<Key>, class Alloc = alloc>
- class set {
- public:
- // typedefs:
- typedef Key key_type;
- typedef Key value_type;
- typedef Compare key_compare;
- typedef Compare value_compare;
- private:
- typedef rb_tree<key_type, value_type,
- identity<value_type>, key_compare, Alloc> rep_type;
- rep_type t; // red-black tree representing set
- public:
- typedef typename rep_type::const_pointer pointer;
- typedef typename rep_type::const_pointer const_pointer;
- typedef typename rep_type::const_reference reference;
- typedef typename rep_type::const_reference const_reference;
- typedef typename rep_type::const_iterator iterator;
- typedef typename rep_type::const_iterator const_iterator;
- typedef typename rep_type::const_reverse_iterator reverse_iterator;
- typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
- typedef typename rep_type::size_type size_type;
- typedef typename rep_type::difference_type difference_type;
- // allocation/deallocation
- set() : t(Compare()) {}
- explicit set(const Compare& comp) : t(comp) {}
- #ifdef __STL_MEMBER_TEMPLATES
- template <class InputIterator>
- set(InputIterator first, InputIterator last)
- : t(Compare()) { t.insert_unique(first, last); }
- template <class InputIterator>
- set(InputIterator first, InputIterator last, const Compare& comp)
- : t(comp) { t.insert_unique(first, last); }
- #else
- set(const value_type* first, const value_type* last)
- : t(Compare()) { t.insert_unique(first, last); }
- set(const value_type* first, const value_type* last, const Compare& comp)
- : t(comp) { t.insert_unique(first, last); }
- set(const_iterator first, const_iterator last)
- : t(Compare()) { t.insert_unique(first, last); }
- set(const_iterator first, const_iterator last, const Compare& comp)
- : t(comp) { t.insert_unique(first, last); }
- #endif /* __STL_MEMBER_TEMPLATES */
- set(const set<Key, Compare, Alloc>& x) : t(x.t) {}
- set<Key, Compare, Alloc>& operator=(const set<Key, Compare, Alloc>& x) {
- t = x.t;
- return *this;
- }
- // accessors:
- key_compare key_comp() const { return t.key_comp(); }
- value_compare value_comp() const { return t.key_comp(); }
- iterator begin() const { return t.begin(); }
- iterator end() const { return t.end(); }
- reverse_iterator rbegin() const { return t.rbegin(); }
- reverse_iterator rend() const { return t.rend(); }
- bool empty() const { return t.empty(); }
- size_type size() const { return t.size(); }
- size_type max_size() const { return t.max_size(); }
- void swap(set<Key, Compare, Alloc>& x) { t.swap(x.t); }
- // insert/erase
- typedef pair<iterator, bool> pair_iterator_bool;
- pair<iterator,bool> insert(const value_type& x) {
- pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
- return pair<iterator, bool>(p.first, p.second);
- }
- iterator insert(iterator position, const value_type& x) {
- typedef typename rep_type::iterator rep_iterator;
- return t.insert_unique((rep_iterator&)position, x);
- }
- #ifdef __STL_MEMBER_TEMPLATES
- template <class InputIterator>
- void insert(InputIterator first, InputIterator last) {
- t.insert_unique(first, last);
- }
- #else
- void insert(const_iterator first, const_iterator last) {
- t.insert_unique(first, last);
- }
- void insert(const value_type* first, const value_type* last) {
- t.insert_unique(first, last);
- }
- #endif /* __STL_MEMBER_TEMPLATES */
- void erase(iterator position) {
- typedef typename rep_type::iterator rep_iterator;
- t.erase((rep_iterator&)position);
- }
- size_type erase(const key_type& x) {
- return t.erase(x);
- }
- void erase(iterator first, iterator last) {
- typedef typename rep_type::iterator rep_iterator;
- t.erase((rep_iterator&)first, (rep_iterator&)last);
- }
- void clear() { t.clear(); }
- // set operations:
- iterator find(const key_type& x) const { return t.find(x); }
- size_type count(const key_type& x) const { return t.count(x); }
- iterator lower_bound(const key_type& x) const {
- return t.lower_bound(x);
- }
- iterator upper_bound(const key_type& x) const {
- return t.upper_bound(x);
- }
- pair<iterator,iterator> equal_range(const key_type& x) const {
- return t.equal_range(x);
- }
- friend bool operator== __STL_NULL_TMPL_ARGS (const set&, const set&);
- friend bool operator< __STL_NULL_TMPL_ARGS (const set&, const set&);
- };
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
// typedefs:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
typedef Compare value_compare;
private:
typedef rb_tree<key_type, value_type,
identity<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing set
public:
typedef typename rep_type::const_pointer pointer;
typedef typename rep_type::const_pointer const_pointer;
typedef typename rep_type::const_reference reference;
typedef typename rep_type::const_reference const_reference;
typedef typename rep_type::const_iterator iterator;
typedef typename rep_type::const_iterator const_iterator;
typedef typename rep_type::const_reverse_iterator reverse_iterator;
typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
typedef typename rep_type::size_type size_type;
typedef typename rep_type::difference_type difference_type;
// allocation/deallocation
set() : t(Compare()) {}
explicit set(const Compare& comp) : t(comp) {}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
set(InputIterator first, InputIterator last)
: t(Compare()) { t.insert_unique(first, last); }
template <class InputIterator>
set(InputIterator first, InputIterator last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
#else
set(const value_type* first, const value_type* last)
: t(Compare()) { t.insert_unique(first, last); }
set(const value_type* first, const value_type* last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
set(const_iterator first, const_iterator last)
: t(Compare()) { t.insert_unique(first, last); }
set(const_iterator first, const_iterator last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
#endif /* __STL_MEMBER_TEMPLATES */
set(const set<Key, Compare, Alloc>& x) : t(x.t) {}
set<Key, Compare, Alloc>& operator=(const set<Key, Compare, Alloc>& x) {
t = x.t;
return *this;
}
// accessors:
key_compare key_comp() const { return t.key_comp(); }
value_compare value_comp() const { return t.key_comp(); }
iterator begin() const { return t.begin(); }
iterator end() const { return t.end(); }
reverse_iterator rbegin() const { return t.rbegin(); }
reverse_iterator rend() const { return t.rend(); }
bool empty() const { return t.empty(); }
size_type size() const { return t.size(); }
size_type max_size() const { return t.max_size(); }
void swap(set<Key, Compare, Alloc>& x) { t.swap(x.t); }
// insert/erase
typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator,bool> insert(const value_type& x) {
pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
return pair<iterator, bool>(p.first, p.second);
}
iterator insert(iterator position, const value_type& x) {
typedef typename rep_type::iterator rep_iterator;
return t.insert_unique((rep_iterator&)position, x);
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_unique(first, last);
}
#else
void insert(const_iterator first, const_iterator last) {
t.insert_unique(first, last);
}
void insert(const value_type* first, const value_type* last) {
t.insert_unique(first, last);
}
#endif /* __STL_MEMBER_TEMPLATES */
void erase(iterator position) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)position);
}
size_type erase(const key_type& x) {
return t.erase(x);
}
void erase(iterator first, iterator last) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)first, (rep_iterator&)last);
}
void clear() { t.clear(); }
// set operations:
iterator find(const key_type& x) const { return t.find(x); }
size_type count(const key_type& x) const { return t.count(x); }
iterator lower_bound(const key_type& x) const {
return t.lower_bound(x);
}
iterator upper_bound(const key_type& x) const {
return t.upper_bound(x);
}
pair<iterator,iterator> equal_range(const key_type& x) const {
return t.equal_range(x);
}
friend bool operator== __STL_NULL_TMPL_ARGS (const set&, const set&);
friend bool operator< __STL_NULL_TMPL_ARGS (const set&, const set&);
};
可以看到红黑树作为set的一个成员,并且调用基本都是转调用到红黑树中的实现,至于map ,multiset,multimap大同小异,都是这么实现的,就不多说
6)hash_set等容器
顾名思义,他们和set,map等行为差不多,只是底层实现以hash表实现,所以查找删除插入是他们的强项,具有常熟平均时间。
hash table的实现有很多种方法,线性探测法,二次探测法,开链法。至于hash_set等的底层hash table实现,则属于这种开链法
也就是准备一定数量的桶子,每个桶子指向一个链表,每个元素直接插入hash后得到的桶子中的链表中,也就省去了碰撞后的搜寻,下面贴上这种hash_table的实现
- template <class Value>
- struct __hashtable_node//链表节点
- {
- __hashtable_node* next;
- Value val;
- };
- template <class Value, class Key, class HashFcn,
- class ExtractKey, class EqualKey, class Alloc = alloc>
- class hashtable;
- template <class Value, class Key, class HashFcn,
- class ExtractKey, class EqualKey, class Alloc>
- struct __hashtable_iterator;
- template <class Value, class Key, class HashFcn,
- class ExtractKey, class EqualKey, class Alloc>
- struct __hashtable_const_iterator;
- template <class Value, class Key, class HashFcn,
- class ExtractKey, class EqualKey, class Alloc>
- struct __hashtable_iterator { //hash表迭代器
- typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>
- hashtable;
- typedef __hashtable_iterator<Value, Key, HashFcn,
- ExtractKey, EqualKey, Alloc>
- iterator;
- typedef __hashtable_const_iterator<Value, Key, HashFcn,
- ExtractKey, EqualKey, Alloc>
- const_iterator;
- typedef __hashtable_node<Value> node;
- typedef forward_iterator_tag iterator_category;
- typedef Value value_type;
- typedef ptrdiff_t difference_type;
- typedef size_t size_type;
- typedef Value& reference;
- typedef Value* pointer;
- node* cur;
- hashtable* ht;
- __hashtable_iterator(node* n, hashtable* tab) : cur(n), ht(tab) {}
- __hashtable_iterator() {}
- reference operator*() const { return cur->val; }
- #ifndef __SGI_STL_NO_ARROW_OPERATOR
- pointer operator->() const { return &(operator*()); }
- #endif /* __SGI_STL_NO_ARROW_OPERATOR */
- iterator& operator++();
- iterator operator++(int);
- bool operator==(const iterator& it) const { return cur == it.cur; }
- bool operator!=(const iterator& it) const { return cur != it.cur; }
- };
template <class Value>
struct __hashtable_node//链表节点
{
__hashtable_node* next;
Value val;
};
template <class Value, class Key, class HashFcn,
class ExtractKey, class EqualKey, class Alloc = alloc>
class hashtable;
template <class Value, class Key, class HashFcn,
class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_iterator;
template <class Value, class Key, class HashFcn,
class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_const_iterator;
template <class Value, class Key, class HashFcn,
class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_iterator { //hash表迭代器
typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>
hashtable;
typedef __hashtable_iterator<Value, Key, HashFcn,
ExtractKey, EqualKey, Alloc>
iterator;
typedef __hashtable_const_iterator<Value, Key, HashFcn,
ExtractKey, EqualKey, Alloc>
const_iterator;
typedef __hashtable_node<Value> node;
typedef forward_iterator_tag iterator_category;
typedef Value value_type;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef Value& reference;
typedef Value* pointer;
node* cur;
hashtable* ht;
__hashtable_iterator(node* n, hashtable* tab) : cur(n), ht(tab) {}
__hashtable_iterator() {}
reference operator*() const { return cur->val; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
iterator& operator++();
iterator operator++(int);
bool operator==(const iterator& it) const { return cur == it.cur; }
bool operator!=(const iterator& it) const { return cur != it.cur; }
};
- static const int __stl_num_primes = 28; //质数个数
- static const unsigned long __stl_prime_list[__stl_num_primes] = //质数数组,既桶子数
- {
- 53, 97, 193, 389, 769,
- 1543, 3079, 6151, 12289, 24593,
- 49157, 98317, 196613, 393241, 786433,
- 1572869, 3145739, 6291469, 12582917, 25165843,
- 50331653, 100663319, 201326611, 402653189, 805306457,
- 1610612741, 3221225473ul, 4294967291ul
- };
- inline unsigned long __stl_next_prime(unsigned long n) //全剧函数,获得下一个质数大小
- {
- const unsigned long* first = __stl_prime_list;
- const unsigned long* last = __stl_prime_list + __stl_num_primes;
- const unsigned long* pos = lower_bound(first, last, n);
- return pos == last ? *(last - 1) : *pos;
- }
- template <class Value, class Key, class HashFcn,
- class ExtractKey, class EqualKey,
- class Alloc>
- class hashtable {
- public:
- typedef Key key_type;
- typedef Value value_type;
- typedef HashFcn hasher;
- typedef EqualKey key_equal;
- 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;
- hasher hash_funct() const { return hash; }
- key_equal key_eq() const { return equals; }
- private:
- hasher hash;
- key_equal equals;
- ExtractKey get_key;
- typedef __hashtable_node<Value> node;
- typedef simple_alloc<node, Alloc> node_allocator;
- vector<node*,Alloc> buckets;
- size_type num_elements;
- public:
- typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,
- Alloc>
- iterator;
- typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,
- Alloc>
- const_iterator;
- friend struct
- __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;
- friend struct
- __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;
- public:
- hashtable(size_type n,
- const HashFcn& hf,
- const EqualKey& eql,
- const ExtractKey& ext)
- : hash(hf), equals(eql), get_key(ext), num_elements(0)
- {
- initialize_buckets(n);
- }
- hashtable(size_type n,
- const HashFcn& hf,
- const EqualKey& eql)
- : hash(hf), equals(eql), get_key(ExtractKey()), num_elements(0)
- {
- initialize_buckets(n);
- }
- hashtable(const hashtable& ht)
- : hash(ht.hash), equals(ht.equals), get_key(ht.get_key), num_elements(0)
- {
- copy_from(ht);
- }
- hashtable& operator= (const hashtable& ht)
- {
- if (&ht != this) {
- clear();
- hash = ht.hash;
- equals = ht.equals;
- get_key = ht.get_key;
- copy_from(ht);
- }
- return *this;
- }
- ~hashtable() { clear(); }
- size_type size() const { return num_elements; }
- size_type max_size() const { return size_type(-1); }
- bool empty() const { return size() == 0; }
- void swap(hashtable& ht)
- {
- __STD::swap(hash, ht.hash);
- __STD::swap(equals, ht.equals);
- __STD::swap(get_key, ht.get_key);
- buckets.swap(ht.buckets);
- __STD::swap(num_elements, ht.num_elements);
- }
- iterator begin()
- {
- for (size_type n = 0; n < buckets.size(); ++n)
- if (buckets[n])
- return iterator(buckets[n], this);
- return end();
- }
- iterator end() { return iterator(0, this); }
- const_iterator begin() const
- {
- for (size_type n = 0; n < buckets.size(); ++n)
- if (buckets[n])
- return const_iterator(buckets[n], this);
- return end();
- }
- const_iterator end() const { return const_iterator(0, this); }
- friend bool
- operator== __STL_NULL_TMPL_ARGS (const hashtable&, const hashtable&);
- public:
- size_type bucket_count() const { return buckets.size(); }
- size_type max_bucket_count() const
- { return __stl_prime_list[__stl_num_primes - 1]; }
- size_type elems_in_bucket(size_type bucket) const
- {
- size_type result = 0;
- for (node* cur = buckets[bucket]; cur; cur = cur->next)
- result += 1;
- return result;
- }
- pair<iterator, bool> insert_unique(const value_type& obj)
- {
- resize(num_elements + 1);
- return insert_unique_noresize(obj);
- }
- iterator insert_equal(const value_type& obj)
- {
- resize(num_elements + 1);
- return insert_equal_noresize(obj);
- }
- pair<iterator, bool> insert_unique_noresize(const value_type& obj);
- iterator insert_equal_noresize(const value_type& obj);
- #ifdef __STL_MEMBER_TEMPLATES
- template <class InputIterator>
- void insert_unique(InputIterator f, InputIterator l)
- {
- insert_unique(f, l, iterator_category(f));
- }
- template <class InputIterator>
- void insert_equal(InputIterator f, InputIterator l)
- {
- insert_equal(f, l, iterator_category(f));
- }
- template <class InputIterator>
- void insert_unique(InputIterator f, InputIterator l,
- input_iterator_tag)
- {
- for ( ; f != l; ++f)
- insert_unique(*f);
- }
- template <class InputIterator>
- void insert_equal(InputIterator f, InputIterator l,
- input_iterator_tag)
- {
- for ( ; f != l; ++f)
- insert_equal(*f);
- }
- template <class ForwardIterator>
- void insert_unique(ForwardIterator f, ForwardIterator l,
- forward_iterator_tag)
- {
- size_type n = 0;
- distance(f, l, n);
- resize(num_elements + n);
- for ( ; n > 0; --n, ++f)
- insert_unique_noresize(*f);
- }
- template <class ForwardIterator>
- void insert_equal(ForwardIterator f, ForwardIterator l,
- forward_iterator_tag)
- {
- size_type n = 0;
- distance(f, l, n);
- resize(num_elements + n);
- for ( ; n > 0; --n, ++f)
- insert_equal_noresize(*f);
- }
- #else /* __STL_MEMBER_TEMPLATES */
- void insert_unique(const value_type* f, const value_type* l)
- {
- size_type n = l - f;
- resize(num_elements + n);
- for ( ; n > 0; --n, ++f)
- insert_unique_noresize(*f);
- }
- void insert_equal(const value_type* f, const value_type* l)
- {
- size_type n = l - f;
- resize(num_elements + n);
- for ( ; n > 0; --n, ++f)
- insert_equal_noresize(*f);
- }
- void insert_unique(const_iterator f, const_iterator l)
- {
- size_type n = 0;
- distance(f, l, n);
- resize(num_elements + n);
- for ( ; n > 0; --n, ++f)
- insert_unique_noresize(*f);
- }
- void insert_equal(const_iterator f, const_iterator l)
- {
- size_type n = 0;
- distance(f, l, n);
- resize(num_elements + n);
- for ( ; n > 0; --n, ++f)
- insert_equal_noresize(*f);
- }
- #endif /*__STL_MEMBER_TEMPLATES */
- reference find_or_insert(const value_type& obj);
- iterator find(const key_type& key)
- {
- size_type n = bkt_num_key(key);
- node* first;
- for ( first = buckets[n];
- first && !equals(get_key(first->val), key);
- first = first->next)
- {}
- return iterator(first, this);
- }
- const_iterator find(const key_type& key) const
- {
- size_type n = bkt_num_key(key);
- const node* first;
- for ( first = buckets[n];
- first && !equals(get_key(first->val), key);
- first = first->next)
- {}
- return const_iterator(first, this);
- }
- size_type count(const key_type& key) const
- {
- const size_type n = bkt_num_key(key);
- size_type result = 0;
- for (const node* cur = buckets[n]; cur; cur = cur->next)
- if (equals(get_key(cur->val), key))
- ++result;
- return result;
- }
- pair<iterator, iterator> equal_range(const key_type& key);
- pair<const_iterator, const_iterator> equal_range(const key_type& key) const;
- size_type erase(const key_type& key);
- void erase(const iterator& it);
- void erase(iterator first, iterator last);
- void erase(const const_iterator& it);
- void erase(const_iterator first, const_iterator last);
- void resize(size_type num_elements_hint);
- void clear();
- private:
- size_type next_size(size_type n) const { return __stl_next_prime(n); }
- void initialize_buckets(size_type n)
- {
- const size_type n_buckets = next_size(n);
- buckets.reserve(n_buckets);
- buckets.insert(buckets.end(), n_buckets, (node*) 0);
- num_elements = 0;
- }
- size_type bkt_num_key(const key_type& key) const
- {
- return bkt_num_key(key, buckets.size());
- }
- size_type bkt_num(const value_type& obj) const
- {
- return bkt_num_key(get_key(obj));
- }
- size_type bkt_num_key(const key_type& key, size_t n) const
- {
- return hash(key) % n;
- }
- size_type bkt_num(const value_type& obj, size_t n) const
- {
- return bkt_num_key(get_key(obj), n);
- }
- node* new_node(const value_type& obj)
- {
- node* n = node_allocator::allocate();
- n->next = 0;
- __STL_TRY {
- construct(&n->val, obj);
- return n;
- }
- __STL_UNWIND(node_allocator::deallocate(n));
- }
- void delete_node(node* n)
- {
- destroy(&n->val);
- node_allocator::deallocate(n);
- }
- void erase_bucket(const size_type n, node* first, node* last);
- void erase_bucket(const size_type n, node* last);
- void copy_from(const hashtable& ht);
- };
static const int __stl_num_primes = 28; //质数个数
static const unsigned long __stl_prime_list[__stl_num_primes] = //质数数组,既桶子数
{
53, 97, 193, 389, 769,
1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433,
1572869, 3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189, 805306457,
1610612741, 3221225473ul, 4294967291ul
};
inline unsigned long __stl_next_prime(unsigned long n) //全剧函数,获得下一个质数大小
{
const unsigned long* first = __stl_prime_list;
const unsigned long* last = __stl_prime_list + __stl_num_primes;
const unsigned long* pos = lower_bound(first, last, n);
return pos == last ? *(last - 1) : *pos;
}
template <class Value, class Key, class HashFcn,
class ExtractKey, class EqualKey,
class Alloc>
class hashtable {
public:
typedef Key key_type;
typedef Value value_type;
typedef HashFcn hasher;
typedef EqualKey key_equal;
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;
hasher hash_funct() const { return hash; }
key_equal key_eq() const { return equals; }
private:
hasher hash;
key_equal equals;
ExtractKey get_key;
typedef __hashtable_node<Value> node;
typedef simple_alloc<node, Alloc> node_allocator;
vector<node*,Alloc> buckets;
size_type num_elements;
public:
typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,
Alloc>
iterator;
typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,
Alloc>
const_iterator;
friend struct
__hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;
friend struct
__hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;
public:
hashtable(size_type n,
const HashFcn& hf,
const EqualKey& eql,
const ExtractKey& ext)
: hash(hf), equals(eql), get_key(ext), num_elements(0)
{
initialize_buckets(n);
}
hashtable(size_type n,
const HashFcn& hf,
const EqualKey& eql)
: hash(hf), equals(eql), get_key(ExtractKey()), num_elements(0)
{
initialize_buckets(n);
}
hashtable(const hashtable& ht)
: hash(ht.hash), equals(ht.equals), get_key(ht.get_key), num_elements(0)
{
copy_from(ht);
}
hashtable& operator= (const hashtable& ht)
{
if (&ht != this) {
clear();
hash = ht.hash;
equals = ht.equals;
get_key = ht.get_key;
copy_from(ht);
}
return *this;
}
~hashtable() { clear(); }
size_type size() const { return num_elements; }
size_type max_size() const { return size_type(-1); }
bool empty() const { return size() == 0; }
void swap(hashtable& ht)
{
__STD::swap(hash, ht.hash);
__STD::swap(equals, ht.equals);
__STD::swap(get_key, ht.get_key);
buckets.swap(ht.buckets);
__STD::swap(num_elements, ht.num_elements);
}
iterator begin()
{
for (size_type n = 0; n < buckets.size(); ++n)
if (buckets[n])
return iterator(buckets[n], this);
return end();
}
iterator end() { return iterator(0, this); }
const_iterator begin() const
{
for (size_type n = 0; n < buckets.size(); ++n)
if (buckets[n])
return const_iterator(buckets[n], this);
return end();
}
const_iterator end() const { return const_iterator(0, this); }
friend bool
operator== __STL_NULL_TMPL_ARGS (const hashtable&, const hashtable&);
public:
size_type bucket_count() const { return buckets.size(); }
size_type max_bucket_count() const
{ return __stl_prime_list[__stl_num_primes - 1]; }
size_type elems_in_bucket(size_type bucket) const
{
size_type result = 0;
for (node* cur = buckets[bucket]; cur; cur = cur->next)
result += 1;
return result;
}
pair<iterator, bool> insert_unique(const value_type& obj)
{
resize(num_elements + 1);
return insert_unique_noresize(obj);
}
iterator insert_equal(const value_type& obj)
{
resize(num_elements + 1);
return insert_equal_noresize(obj);
}
pair<iterator, bool> insert_unique_noresize(const value_type& obj);
iterator insert_equal_noresize(const value_type& obj);
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert_unique(InputIterator f, InputIterator l)
{
insert_unique(f, l, iterator_category(f));
}
template <class InputIterator>
void insert_equal(InputIterator f, InputIterator l)
{
insert_equal(f, l, iterator_category(f));
}
template <class InputIterator>
void insert_unique(InputIterator f, InputIterator l,
input_iterator_tag)
{
for ( ; f != l; ++f)
insert_unique(*f);
}
template <class InputIterator>
void insert_equal(InputIterator f, InputIterator l,
input_iterator_tag)
{
for ( ; f != l; ++f)
insert_equal(*f);
}
template <class ForwardIterator>
void insert_unique(ForwardIterator f, ForwardIterator l,
forward_iterator_tag)
{
size_type n = 0;
distance(f, l, n);
resize(num_elements + n);
for ( ; n > 0; --n, ++f)
insert_unique_noresize(*f);
}
template <class ForwardIterator>
void insert_equal(ForwardIterator f, ForwardIterator l,
forward_iterator_tag)
{
size_type n = 0;
distance(f, l, n);
resize(num_elements + n);
for ( ; n > 0; --n, ++f)
insert_equal_noresize(*f);
}
#else /* __STL_MEMBER_TEMPLATES */
void insert_unique(const value_type* f, const value_type* l)
{
size_type n = l - f;
resize(num_elements + n);
for ( ; n > 0; --n, ++f)
insert_unique_noresize(*f);
}
void insert_equal(const value_type* f, const value_type* l)
{
size_type n = l - f;
resize(num_elements + n);
for ( ; n > 0; --n, ++f)
insert_equal_noresize(*f);
}
void insert_unique(const_iterator f, const_iterator l)
{
size_type n = 0;
distance(f, l, n);
resize(num_elements + n);
for ( ; n > 0; --n, ++f)
insert_unique_noresize(*f);
}
void insert_equal(const_iterator f, const_iterator l)
{
size_type n = 0;
distance(f, l, n);
resize(num_elements + n);
for ( ; n > 0; --n, ++f)
insert_equal_noresize(*f);
}
#endif /*__STL_MEMBER_TEMPLATES */
reference find_or_insert(const value_type& obj);
iterator find(const key_type& key)
{
size_type n = bkt_num_key(key);
node* first;
for ( first = buckets[n];
first && !equals(get_key(first->val), key);
first = first->next)
{}
return iterator(first, this);
}
const_iterator find(const key_type& key) const
{
size_type n = bkt_num_key(key);
const node* first;
for ( first = buckets[n];
first && !equals(get_key(first->val), key);
first = first->next)
{}
return const_iterator(first, this);
}
size_type count(const key_type& key) const
{
const size_type n = bkt_num_key(key);
size_type result = 0;
for (const node* cur = buckets[n]; cur; cur = cur->next)
if (equals(get_key(cur->val), key))
++result;
return result;
}
pair<iterator, iterator> equal_range(const key_type& key);
pair<const_iterator, const_iterator> equal_range(const key_type& key) const;
size_type erase(const key_type& key);
void erase(const iterator& it);
void erase(iterator first, iterator last);
void erase(const const_iterator& it);
void erase(const_iterator first, const_iterator last);
void resize(size_type num_elements_hint);
void clear();
private:
size_type next_size(size_type n) const { return __stl_next_prime(n); }
void initialize_buckets(size_type n)
{
const size_type n_buckets = next_size(n);
buckets.reserve(n_buckets);
buckets.insert(buckets.end(), n_buckets, (node*) 0);
num_elements = 0;
}
size_type bkt_num_key(const key_type& key) const
{
return bkt_num_key(key, buckets.size());
}
size_type bkt_num(const value_type& obj) const
{
return bkt_num_key(get_key(obj));
}
size_type bkt_num_key(const key_type& key, size_t n) const
{
return hash(key) % n;
}
size_type bkt_num(const value_type& obj, size_t n) const
{
return bkt_num_key(get_key(obj), n);
}
node* new_node(const value_type& obj)
{
node* n = node_allocator::allocate();
n->next = 0;
__STL_TRY {
construct(&n->val, obj);
return n;
}
__STL_UNWIND(node_allocator::deallocate(n));
}
void delete_node(node* n)
{
destroy(&n->val);
node_allocator::deallocate(n);
}
void erase_bucket(const size_type n, node* first, node* last);
void erase_bucket(const size_type n, node* last);
void copy_from(const hashtable& ht);
};
其中涉及到重建表格的判断值得一提,判断表格是否需要重建的原则是拿总元素个数和桶子数比较,桶子用vector容器代替,如果前者大于后者,就重建表格,这样判断肯定有一定的理由。我觉得如果经过一番严密的数学计算的话这种判断重建应该是可以控制插入删除等操作的时间复杂度在一定范围内,以达到高效的目的而不会让一条链很长。
然后hash_set等容器就是把hash_table作为一个成员类似set等容器直接转调用就OK了。
ps:看了这些个STL源码发现很多代码分成多个函数宁愿来转调用也不把多个函数组成一个函数,而且前几天反汇编过过一个转调用发现在汇编里所谓的转调用已经不用call跳转了,相信这都是编译器的功劳。所以相信编译器大胆的去转调用吧(这。。),事实上很多看起来提升效率的做法不仅没有提升效率反而降低了可读性、封装性等,所以就不要吝啬一个个调用吧,编译器的强大超乎想象。。。。
今天把STL算法那章看完了,其实对于STL的算法实现也没什么好说的,除了所有算法都提供一个迭代器接口以支持任何类型的算法实作(当然对于效率无所不用其极的SGI STL来说,各种特化版本是免不了的,其中也用到各种型别萃取达到激活重载机制以达到最佳效率的技术)。
想要提一下的就是其中的sort算法(真正的无所不用其极),在其中第一次看到一个名叫内省排序(混合式排序)的算法,主体依然是快速排序,但是避免了快速排序的二次复杂度的恶化,也就是将效率至少维持在O(NlogN)。
首先这个混合排序在排序过程进行了序列大小的评估,根据评估结果决定继续采用快排还是退出并执行插入排序(快排因为产生许多自序列排序的递归调用而足够复杂,以至于在小数据量的时候插入排序速度甚至快过快排),就我在STL源码剖析上看到的这个值是16,然后快排在行进过程中还会进行中值分割,即取最左、中、右的值取中值以尽量避免分割的恶化。同时还对具体的序列大小进行最大分割次数的计算(即快排在最佳分割情况下总共分割出多少个子序列),然后将这个值作为算法的一个参数参与到运算中,每分割排序一次值减1。当算法行进并趋向一个恶性分割的话(比如枢纽元素为最小,出现左边为空的情况),转而调用堆排序,以将效率维持在O(NlogN)上界,大概就是这样(SGI STL对于效率真是无所不用其极),下面就附上内省排序代码
- template <class Size> //最大分割次数计算
- inline Size __lg(Size n) {
- Size k;
- for (k = 0; n > 1; n >>= 1) ++k;
- return k;
- }
template <class Size> //最大分割次数计算
inline Size __lg(Size n) {
Size k;
for (k = 0; n > 1; n >>= 1) ++k;
return k;
}
- template <class RandomAccessIterator>
- void __final_insertion_sort(RandomAccessIterator first,
- RandomAccessIterator last) {
- if (last - first > __stl_threshold) {
- __insertion_sort(first, first + __stl_threshold);
- __unguarded_insertion_sort(first + __stl_threshold, last);
- }
- else
- __insertion_sort(first, last);
- }
- template <class RandomAccessIterator, class T, class Size>
- void __introsort_loop(RandomAccessIterator first,
- RandomAccessIterator last, T*,
- Size depth_limit) {
- while (last - first > __stl_threshold) {
- if (depth_limit == 0) {
- partial_sort(first, last, last); //STL的局部排序算法,内部就是个堆排序了
- return;
- }
- --depth_limit;
- RandomAccessIterator cut = __unguarded_partition
- (first, last, T(__median(*first, *(first + (last - first)/2),
- *(last - 1)))); //中值枢纽的选择
- __introsort_loop(cut, last, value_type(first), depth_limit); //递归
- last = cut;
- }
- }
- template <class RandomAccessIterator>
- inline void sort(RandomAccessIterator first, RandomAccessIterator last) {
- if (first != last) {
- __introsort_loop(first, last, value_type(first), __lg(last - first) * 2); //内省排序
- __final_insertion_sort(first, last); //插入排序
- }
- }
template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last) {
if (last - first > __stl_threshold) {
__insertion_sort(first, first + __stl_threshold);
__unguarded_insertion_sort(first + __stl_threshold, last);
}
else
__insertion_sort(first, last);
}
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
RandomAccessIterator last, T*,
Size depth_limit) {
while (last - first > __stl_threshold) {
if (depth_limit == 0) {
partial_sort(first, last, last); //STL的局部排序算法,内部就是个堆排序了
return;
}
--depth_limit;
RandomAccessIterator cut = __unguarded_partition
(first, last, T(__median(*first, *(first + (last - first)/2),
*(last - 1)))); //中值枢纽的选择
__introsort_loop(cut, last, value_type(first), depth_limit); //递归
last = cut;
}
}
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {
if (first != last) {
__introsort_loop(first, last, value_type(first), __lg(last - first) * 2); //内省排序
__final_insertion_sort(first, last); //插入排序
}
}
看完算法这章也就接近尾声了,明天应该就能把STL源码剖析看完了哈哈
//书看完了,继续接着在这写好了
在最后2章看到了仿函数和配接器的实现(不得不惊叹C++太美妙了)
首先仿函数,顾名思义就是模仿函数的行为,说到底就是重载了调用操作符的对象,STL的大部分算法都提供了一个仿函数接口(也就是说可以定义算法进行关键判断的处理可以交由我们DIY,例如对于sort算法,利用这个接口我们可以随意定义排序过程中“真”的含义,比如大于(结果就是递减排序),小于(结果就是递增排序)以至于各种你能想到的搞怪的表达式判断),再加上模版泛型编程,灵活度可想而知。下面就写一个例子好了
- template<typename T>
- struct op
- {
- bool operator() (const T& arg1,const T& arg2)
- {
- return arg1 > arg2;
- }
- };
- int main()
- {
- vector<int> iv;
- srand(time(0));
- for(int i=0;i<10;i++)
- iv.push_back(rand()%100 );
- sort(iv.begin(), iv.end(), op<int>() );
- copy(iv.begin(), iv.end(), ostream_iterator<int>(cout, " "));
- return 0;
- }
template<typename T>
struct op
{
bool operator() (const T& arg1,const T& arg2)
{
return arg1 > arg2;
}
};
int main()
{
vector<int> iv;
srand(time(0));
for(int i=0;i<10;i++)
iv.push_back(rand()%100 );
sort(iv.begin(), iv.end(), op<int>() );
copy(iv.begin(), iv.end(), ostream_iterator<int>(cout, " "));
return 0;
}
这样就能看到排序结果降序排列,如此简单。不过如果需要非常复杂的表达式,并且各种表达式相互组合,这样一个简单的函数对象就不够了,这时候就需要配接器将各种表达式配接成一个复杂的表达式如f(g(x),t(y))之类。为了让自己的仿函数具有配接功能,就必须继承unary_function或binary_function类(当然没有任何额外负担,仅仅是获得一些性别定义提供萃取功能,达到配接目的)。
还是继续上例子吧,为了更好说明我就不继承而是自己实现配接功能
- /*
- template<typename T>
- struct op:public binary_function<T, T, bool>
- {
- bool operator() (const T& arg1,const T& arg2) const
- {
- return arg1 > arg2;
- }
- };
- */
- template<typename T>
- struct op
- {
- typedef T first_argument_type;
- typedef T second_argument_type;
- typedef bool result_type;
- bool operator() (const T& arg1,const T& arg2) const
- {
- return arg1 > arg2;
- }
- };
- int main()
- {
- vector<int> iv;
- srand(time(0));
- for(int i=0;i<10;i++)
- iv.push_back(rand()%100 );
- sort(iv.begin(), iv.end(), op<int>() );
- copy(iv.begin(), iv.end(), ostream_iterator<int>(cout, " "));
- cout << endl << count_if(iv.begin(), iv.end(), bind2nd(op<int>(), 50) );
- getchar();
- return 0;
- }
/*
template<typename T>
struct op:public binary_function<T, T, bool>
{
bool operator() (const T& arg1,const T& arg2) const
{
return arg1 > arg2;
}
};
*/
template<typename T>
struct op
{
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
bool operator() (const T& arg1,const T& arg2) const
{
return arg1 > arg2;
}
};
int main()
{
vector<int> iv;
srand(time(0));
for(int i=0;i<10;i++)
iv.push_back(rand()%100 );
sort(iv.begin(), iv.end(), op<int>() );
copy(iv.begin(), iv.end(), ostream_iterator<int>(cout, " "));
cout << endl << count_if(iv.begin(), iv.end(), bind2nd(op<int>(), 50) );
getchar();
return 0;
}
可以看到继承以实现配接的对象我注释掉了,其实和下面那个实现一样,就是定义几个型别实现traits即型别萃取
至于迭代器配接如back_inserter,front_inserter,inserter,还有逆向迭代器,流迭代器等,都是一种配接器,实现起来都是将迭代器作为本身的一个成员,然后根据需要修改相关行为以配接算法等各种需要。