之前在学习STL库中的析构工具destory()时,提到过这样一句话,此函数设法找到元素的数值型别,进而利用__type_traits<>求取适当措施。一直难以理解,现在自己总结了下自己对萃取技术的理解。
让自己困惑的程序:
template<class T>
void destroy(T *pointer)
{
pointer->~T();
}
template<calss ForwardIterator>
void destroy(ForwardIterator first, ForwardIterator last)
{
__destroy(first, last, value_type(first));
}
template<class ForwardIterator, class T>
void __destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first, last, trivial_destructor());
}
//注意这里判断元素的数值型别是否有trivial destructor, 由于是__false_type,所以要对这个型别进行析构,所以
//轮询调用destroy()进行析构
template<class ForwardIterator>
void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
for( ; first < last; ++first){
destroy(&*first);
}
}
//由于是__true_type所以不用进行析构操作,系统会采用内存直接处理操作例如free
template<class ForwardIterator>
void __destroy_aux(ForwardIterator first, ForwardIterator last, __true_type)
{
}
这里有困惑,那么看看萃取机制
萃取技术,就是当函数,类这种一些封装的通用算法中的某些部分会因为数据类型不同而导致处理的逻辑不同,然而我们又不想因为数据类型的差异而修改算法本身的封装,所以采用萃取机制来解决这一问题。从而实现同一种操作因类型不同而异的效果。因此在STL中为了提供通用的操作而又不想损失效率就采用traits编程技巧。
__type_traits负责萃取型别特性,通常我们关注的型别特性有是否具备non-trivial defalt ctor?是否具备non-trivial copy ctor?是否具备non-trivial assignment operator?是否具备non-trivial dtor?如果答案是否定的(也就是说具备这些特性)就对这个型别进行构造,析构, 拷贝, 赋值等操作,这样可以采用最有效率的措施。(比如一些自己定义的类,或者不是普通类型比如string类, 对象等,就要进行这样的操作)如果答案是确定的(也就是说不具备这些特性,例如int, float. double, char等普通的类型就不具备这种特性)这些类型为了提高效率直接采用内存处理操作,例如malloc() memcpy(),所以这种机制对于大规模操作频繁的容器有着显著的效率的提升。
例如:我们准备对一个元素型别未知的数组进行拷贝操作,如果我们知道这个元素型别是否有一个trivial copy constructor,以便我们决定是否使用快速的memcpy(),还是使用慢速的拷贝构造函数。
下面是SGI中<type_traits.h>中的__type_traits,提供的一种机制,允许针对不同型别属性,在编译期完成函数派送决定(意思是在编译期就决定是采用快速的内存直接处理操作还是采用慢速的构造,析构,拷贝,赋值操作)
struct __true_type{};
struct __false_type{};
template<calss type>
struct __type_traits{
typedef __true_type this_dummy_must_be_first;
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;
};
SGI把所有的内嵌型别都定义为__false_type,定义出最保守的值。但同时SGI还针对每一个型别设计了适当的__type_traits的特化版本
例如:char类型,因为对char类型进行初始化,删除,赋值,复制,都可以通过快速的内存直接处理操作,所以这里将__false_type改为__true_type不具备这些特性。
__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;
}
了解这些,现在回头看看最上面那个之前看不懂的destroy()析构工具,目的是将[first, last)范围ie内的所有对象析构掉,我们不知道这个范围有多大,如果 很大,然而每个对象的析构函数都无关痛痒,那么一次次调用这些析构会哪数会降低效率,因此这里利用value_type()获得迭代器所指对象的型别,在利用__type_traits<T>判断该型别的析构函数是否无关痛痒,如果是__true_type则什么都不做,系统会采用内存直接处理操作,如果是__false_type才采用循环方式对每个对象进行析构。