STL对于性能的要求非常的严格,任何一点无意义的操作都会严重影响其中容器或算法的性能,即使只是一条语句。在高频率的使用下,这种浪费将会无限扩大。type_traits的作用之一就是提高性能。
当我们在进行对象的析构(destroy)操作时,如果对象为内置对象(如int,char,float,pointer)或其数据成员包含内置对象,因为其析构操作由编译器内置执行,所以我们对其进行析构函数的调用是毫无意义的。
试想,我们创造一个容器,其中包含的对象皆是内置类型的对象,若我们对如此多的对象逐一调用一个无关痛痒的destroy操作,那此容器的效率将会大大降低。
所以我们需要一种手段,将那些有着无意义析构函数(trivial destructor)的类型挑选出来进行特殊处理:他们的析构操作我们什么也不需要做,交由编译器处理吧。这种手段就是type_traits,其将所有对象类型分为两类,一种的析构函数有意义,另一种的析构函数没有意义。这样我们就能分门别类的析构他们。
下面我们一起探讨下如何实现type_traits。
首先我们需要的是一个可以在函数间传递的"信息"。这个信息应该准确告诉我们,我们应该调用析构操作的哪个重载版本。众所周知,在函数间传递信息的方式有两种:参数或返回值。最简单直接的方式就是参数传递。但传递参数实质是对象或对象的拷贝的传递,所以,我们先创建两个对象,这两个对象什么也不干,唯一的作用就是帮助我们区分,待析构对象到底属于两类中的哪一类。
这两个对象长这样:
struct _true_type{};//无意义的析构函数
struct _false_type{};//有意义的析构函数
说什么也不干,就什么也不干!这两个对象里什么也没有,即使频繁的作为参数传递也不会引起太多浪费(比起大量无意义的析构函数来说确实是九牛一毛)。
那我们如何利用这两个对象呢?
这时我们就需要利用模板特例化来分而治之:
我们先创建一个基础类模板,先将所有类型都标为_false_type:
template<typename T>
struct type_traits
{
typedef _false_type has_trivial_default_constructor;//默认构造函数是否有意义?
typedef _false_type has_trivial_copy_constructor;//拷贝构造函数是否有意义?
typedef _false_type has_trivial_assgignment_constructor;//拷贝赋值操作是否有意义?
typedef _false_type has_trivial_destructor;//析构函数是否有意义?
/*POD意指Plain Old Data,也就是标量型别或传统的C struct(传统的C struct只能
包含数据成员,不能包含函数成员。也就是所谓的聚合类。POD型别必然包含无意义
的ctor/dtor/copy/assignment函数。
*/
typedef _false_type is_POD_type;//是否为Plain Old Data?
};
然后,我们再为每个内置类型对象实现其特例化:
#ifndef _STL_TEMPLATE_NULL
#define _STL_TEMPLATE_NULL template<>
#endif
_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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
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_assgignment_constructor;
typedef _true_type has_trivial_destructor;
typedef _true_type is_POD_type;
};
template<typename T>
struct type_traits <T*>
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assgignment_constructor;
typedef _true_type has_trivial_destructor;
typedef _true_type is_POD_type;
};
当我们使用他们,例如进行析构操作时,我们可以实现两个重载函数,用_true_type对象或_false_type对象来区分他们:
void _destroy(Iterator first, T value)
{
typedef typename type_traits<T>::has_trivial_destructor trivial_destructor;
_destroy_aux(first, trivial_destructor());
}
template<typename Iterator>
void _destroy_aux(Iterator first, _false_type)
{
destroy_main(&*first);//有意义的析构函数,析构他!
}
template<typename Iterator>
void _destroy_aux(Iterator first, _true_type){}//无意义的析构函数,那就不管我的事咯~
有了_type_traits后,我们就可以实现更有效率的拷贝、赋值、析构操作了!