STL源码剖析笔记<三> 智能指针、traits技法

智能指针与迭代器

STL的中心思想是把数据容器和算法分开设计,C++使用泛型技术class template和function template技术都可以实现,但难点却在于将两者配合好。算法的设计过多的依赖容器,容器的改动会造成大量算法函数的随之改动,迭代器便是用来粘合算法与数据容器的技术

迭代器实际是一种智能指针

迭代器行为类似于指针,其最为常见的工作是取值operator*与成员访问operator->
但是由于C++没有C#那种内存管理回收机制,所以容易造成内存泄露。为了解决这个问题,C++中有auto_ptr,shared_ptr等类用来防止内存泄露。

auto_ptr

auto_ptr的源代码在头文件
auto_ptr管理从new申请的一个对象资源,auto_ptr的析构函数会delete指向的对象,所以在使用的时候不用delete

1
2
3
4
5
6
void func()
{
auto_ptr<string> ps(new string("lalala"));
cout<<*ps<<endl;
cout<<ps->size()<<endl;
//离开前不用delete,auto_ptr会自动释放

auto_ptr只能用来管理一个对象的指针。

1
2
3
4
5
6
7
8
9
10
11
12
struct MyStruct
{
MyStruct(){cout<<"MyStruct()\n";}
~MyStruct(){cout<<"~MyStruct()\n";}
int i;
int j;
};
{
//compile OK, but we cannot use auto_ptr this way!
auto_ptr<MyStruct> pStructArr(new MyStruct[5]);
}

由于auto_ptr内部维护的指针资源只能管理一个对象,在释放资源时使用的是delete而不是 delete[], 因此这种使用方式会导致资源的泄露。

auto_ptr的赋值或复制要格外小心
对于普通的指针,进行复制(或赋值)时,实际是复制(或赋值)指针的地址,通过复制(或赋值),使得两个指针指向同一个地址。但是auto_ptr 却不同,在复制(或赋值)auto_ptr 对象之后,原来的auto_ptr 对象(右侧的对象)放弃资源的使用权,而新的auto_ptr 对象(左侧的)则拥有该基础对象的使用权

1
2
auto_ptr<int> pInt(new int(3));
auto_ptr<int> pInt2 = pInt;

首先pInt用于管理动态分配的整型指针,pInt2 = pInt进行复制后,pInt 被重置为未绑定的状态,而pInt2 此时拥有了对整型指针的管理权。需要注意的是,在复制或赋值时,如果pInt2 已经绑定了一个指针,那么会首先释放该指针的资源,然后再绑定新的资源。auto_ptr可以通过.get()得到原始指针看是否绑定对象

根据auto_ptr的特点,在使用auto_ptr 时遵循如下的原则:

  • 不要使用auto_ptr 绑定指向静态分配对象的指针。

  • 不要使用两个auto_ptr 对象指向同一个对象。

  • 不要使用auto_ptr 对象保存指向动态分配数组的指针。

  • 不要将auto_ptr 对象存储在容器中,因为它不满足容易对存储对象赋值和复制的条件要求。

shared_ptr

在C++11中,有了更好的智能指针shared_ptr,其特点最接近原始的指针。不仅能够自由的赋值和拷贝,而且可以安全的用在标准容器中。
shared_ptr 和 auto_ptr 一样,也是重载了 -> 和 * 操作符,使用 get()函数可以得到原始的指针,auto_ptr 提供了隐式的bool类型转换,可以直接用于判断auto_ptr对象是否绑定了指针资源。use_cout()用于返回当前资源的引用计数。

对auto_ptr进行复制或者拷贝,实质是增添了引用计数, 和 auto_ptr 不同的是,reset() 函数在 shared_ptr 中的作用是对引用计数减1,并不会立即释放资源。知道引用计数减为0时,资源才得到真正的释放。use_count()在实际的应用中很少使用,一般是用于调试,shared_ptr提供了一个高效的函数 unique(),同use_count==1等效,当维护的指针资源引用计数为1时,返回true。

make_shared

使用shared_ptr 避免了手动使用delete来释放由new申请的资源,标准库也引入了make_shared函数来创建一个shared_ptr对象,使用shared_ptr和make_shared,你的代码里就可以使new和delete消失,同时又不必担心内存的泄露。

1
shared_ptr<string> ps=make_shared<string>("lalala");

类型转换

shared_ptr 的类型转换不能使用一般的static_cast,这种方式进行的转换会导致转换后的指针无法再被shared_ptr对象正确的管理。应该使用专门用于shared_ptr类型转换的 static_pointer_cast() , const_pointer_cast() 和 dynamic_pointer_cast().例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include"stdafx.h"
#include<iostream>
#include<memory>
#include<string>
using namespace std;
class BaseClass
{
public:
BaseClass(){}
~BaseClass(){}
public:
virtual void Func() { cout<<"BaseClass::Func()\n";}
};
class DeriveClass : public BaseClass
{
public:
DeriveClass(){}
~DeriveClass(){}
public:
virtual void Func() override { cout << "DeriveClass::Func()\n";}
};
int main()
{
shared_ptr<BaseClass> spBase( new BaseClass() );
spBase->Func(); // 输出 BaseClass::Func()
shared_ptr<DeriveClass> spDerive( new DeriveClass() );
spDerive->Func();// 输出 DeriveClass::Func()
shared_ptr<BaseClass> spBase2 = dynamic_pointer_cast<BaseClass>(spDerive);
spBase2->Func();// 输出 DeriveClass::Func()
system("pause");
return 0;
}

traits编程技法

介绍完了智能指针,我们再来理解traits编程技法
先看一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//对于int类的求和函数
int sum(int *a , int n)
{
int sum = 0 ;
for (int i = 0 ; i < n ; i++) {
sum += *a++;
}
return sum;
}
//对于listNode类的求和函数
struct ListNode {
int val;
ListNode * next;
};
int sum(ListNode * head) {
int sum = 0;
ListNode *p = head;
while (p != NULL) {
sum += p->val;
p=p->next;
}
return sum;
}

在sum函数中,我们必须知道容器的元素类型,这关系到函数返回值。既然迭代器设计中不能暴露容器的实现细节,那么我们在算法中是不可能知道容器元素的类型,因此,必须设计出一个机制,能够提取出容器中元素的类型。看看如下示例代码:
template参数推导机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <iostream>
using namespace std;
//此函数中并不知道iter所指的元素型别,而是通过模板T来获取的
template <class I, class T1 ,class T>
T sum_impl(I iter ,T1 n , T t) {
T sum = 0;//通过模板的特性,可以获取I所指之物的型别,此处为int
//这里做func应该做的工作
for(int i = 0 ; i < n ;i++){
sum+=*iter++;
}
return sum;
}
template <class I , class T1>
inline T1 sum(I iter , T1 n) {//此处暴露了template参数推导机制的缺陷,在型别用于返回值时便束手无策
return sum_impl(iter , n ,*iter);
}
int main() {
int a[5] = {1,2,3,4,5};
int sum1 = sum(a , 5);
cout<<sum1<<endl;
}

上例中通过模板的参数推导机制推导出了iter所指之物的型别(int),于是可以定义T sum变量。
然而,迭代器所指之物的型别并非只是”迭代器所指对象的型别“,最常用的迭代器型别有五种,并非任何情况下任何一种都可利用上述的template参数推导机制来获取,而且对于返回值类型,template参数推导机制也束手无策,因此,Traits技法应运而生,解决了这一难题!

内嵌型别机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <iostream>
using namespace std;
//定义一个简单的iterator
template <class T>
struct MyIter{
typedef T value_type; // 内嵌型别声明
T* ptr;
MyIter(T* p =0):ptr(p){}
T& operator*() const {return *ptr;}
//...
};
template <class I>
typename I::value_type // func返回值型别
func(I iter){
return *iter;
}
int main(){
MyIter<int> iter(new int(8));
cout<<func(iter)<<endl;
}

注意,func()函数的返回值型别必须加上关键词typename,因为T是一个template参数,在它被编译器具现化之前,编译器对其一无所知,关键词typename的用意在于告诉编译器这是一个型别,如此才能通过编译。

内嵌型别看起来不错,可以很顺利的提取出迭代器所指型别并克服了template参数推导机制不能用于函数返回值的缺陷。可是,并不是所有的迭代器都是class type,原声指针就不是!如果不是class type,那么就无法声明内嵌型别。但是STL绝对必须接受原生指针作为一个迭代器。因此,必须另行它法!

针对原生指针这类特殊情况,我们很容易想到利用模板偏特化的机制来实现特殊声明,在泛化设计中提供一个特化版本。偏特化的定义是:针对任何template参数更进一步的条件限制所设计出来的一个特化版本。这里,针对上面的MyIter设计出一个适合原生指针的特化版本,如下:

1
2
3
4
5
6
7
template <class T>
struct MyIter <T*>{ //T*代表T为原生指针,这便是T为任意型别的一个更进一步的条件限制
typedef T value_type; // 内嵌型别声明
T* ptr;
MyIter(T* p =0):ptr(p){}
T& operator*() const {return *ptr;}
};

STL专门设计了一个iterator_traits模板类来”萃取“迭代器的特性。其定义如下:

1
2
3
4
5
template <class I>
struct iterator_traits
{
typedef typename I::value_type value_type;
};

这个类如何完成迭代器的型别萃取呢?

1
2
3
4
5
template <class I>
typename iterator_traits<I>::value_type // 通过iterator_traits类萃取I的型别
func(I iter){
return *iter;
}

从表面上来看,这么做只是多了一层间接性,但是带来的好处是极大的!iterator_traits类可以拥有特化版本,如下:

1
2
3
4
5
6
7
8
9
10
11
12
//原生指针特化版本
template <class T>
struct iterator_traits <T*>
{
typedef T value_type;
}
//const指针特化版本
template <class T>
struct iterator_traits <const T*>
{
typedef T value_type;
}

原生指针int*虽然不是一种class type,也可以通过traits取其value,到这里traits的思想就基本明了了!下面就来看看STL只能中”萃取机“的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 用于traits出迭代其所指对象的型别
template <class Iterator>
struct iterator_traits
{
// 迭代器类型, STL提供五种迭代器
typedef typename Iterator::iterator_category iterator_category;
// 迭代器所指对象的型别
// 如果想与STL算法兼容, 那么在类内需要提供value_type定义
typedef typename Iterator::value_type value_type;
// 这个是用于处理两个迭代器间距离的类型
typedef typename Iterator::difference_type difference_type;
// 直接指向对象的原生指针类型
typedef typename Iterator::pointer pointer;
// 这个是对象的引用类型
typedef typename Iterator::reference reference;
};
// 针对指针提供特化版本
template <class T>
struct iterator_traits<T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
// 针对指向常对象的指针提供特化
template <class T>
struct iterator_traits<const T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};

迭代器设计

迭代器型别

value_type
所谓value_type,是指迭代器所指对象的型别。

difference_type
difference_type用来表示两个迭代器之间的距离,因此它也可以用来表示一个容器的最大容量。下面以STL里面的计数功能函数count()为例,来介绍一下difference_type的用法。

1
2
3
4
5
6
7
8
9
template <class I,class T>
typename iterator_traits<I>::difference_type //返回值类型
count(I first , I end , const T& value){
typename iterator_traits<I>::difference_type n = 0;
for( ; first!=end ; ++first){
if(*first == value) ++n;
}
return n;
}

针对原生指针和原生的const指针,iterator_traits的difference_type为ptrdiff_t(long int),特化版本依然可以采用iterator_traits::difference_type来获取型别。

reference_type
从“迭代器所指之物的内容是否可以改变”的角度可以将迭代器分为两种:

  • const迭代器:不允许改变“所指对象之内容”,例如const int* p
  • mutable迭代器:允许改变“所指对象之内容”,例如int* p
    当我们要对一个mutable迭代器进行提领(reference)操作时,获得的不应该是一个右值(右值不允许赋值操作),而应该是一个左值,左值才允许赋值操作。

故:

  • 当p是一个mutable迭代器时,如果其value type是T,那么*p的型别应该为T&;
  • 当p是一个const迭代器时,*p的型别为const T&

pointer type
迭代器可以传回一个指针,指向迭代器所指之物。再迭代器源码中,可以找到如下关于指针和引用的实现:

1
2
Reference operator*() const { return *value; }
pointer operator->() const { return &(operator*()); }

在iterator_traits结构体中需要加入其型别,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <class Iterator>
struct iterator_traits
{
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
}
//针对原生指针的特化版本
template <class T>
struct iterator_traits<T*>
{
typedef T* pointer;
typedef T& reference;
};
//针对原生const指针的特化版本
template <class T>
struct iterator_traits<const T*>
{
typedef const T* pointer;
typedef const T& reference;
};

iterator_category
这一型别代表迭代器的类别,一般分为五类:

  • Input Iterator:只读(read only)
  • Output Iterator:只写(write only)
  • Forward Iterator:允许“写入型”算法在此迭代器所形成的区间上进行读写操作
  • Bidirectional Iterator:可双向移动的迭代器
  • Random Access Iterator:前四种迭代器都只供应一部分指针的算数能力(前三种支持operator++,第四种支- 持operator–),第五种则涵盖所有指针的算数能力,包括p+n,p-n,p[n],p1-p2,p1
1
2
3
4
5
6
// 用于标记迭代器类型
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 {};

为了符合规范,任何迭代器都应该提供五个内嵌型别,以利于Traits萃取,否则就自别与整个STL架构,可能无法与其他STL组件顺利搭配。STL提供了一份iterator class如下:

1
2
3
4
5
6
7
8
9
10
//为避免挂一漏万,每个新设计的迭代器都必须继承自它
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;
};

迭代器源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* 用于标记迭代器类型
*/
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 {};
/**
* 用于traits出迭代其所指对象的型别
*/
template <class Iterator>
struct iterator_traits
{
// 迭代器类型, STL提供五种迭代器
typedef typename Iterator::iterator_category iterator_category;
// 迭代器所指对象的型别
// 如果想与STL算法兼容, 那么在类内需要提供value_type定义
typedef typename Iterator::value_type value_type;
// 这个是用于处理两个迭代器间距离的类型
typedef typename Iterator::difference_type difference_type;
// 直接指向对象的原生指针类型
typedef typename Iterator::pointer pointer;
// 这个是对象的引用类型
typedef typename Iterator::reference reference;
};
/**
* 针对指针提供特化版本
*/
template <class T>
struct iterator_traits<T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
/**
* 针对指向常对象的指针提供特化
*/
template <class T>
struct iterator_traits<const T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};
/**
* 返回迭代器类别
*/
template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&)
{
typedef typename iterator_traits<Iterator>::iterator_category category;
return category();
}
/**
* 返回表示迭代器距离的类型
*/
template <class Iterator>
inline typename iterator_traits<Iterator>::difference_type*
distance_type(const Iterator&)
{
return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
}
/**
* 返回迭代器所指对象的类型
*/
template <class Iterator>
inline typename iterator_traits<Iterator>::value_type*
value_type(const Iterator&)
{
return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
}

迭代器的相关函数设计

distance函数
distance函数用来计算两个迭代器之前的距离。

  • 针对Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator来说,必须逐一累加计算距离
  • 针对random_access_iterator来说,支持两个迭代器相减,所以直接相减就能得到距离
    其具体实现如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    /**
    * 针对Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator
    * 这四种函数,需要逐一累加来计算距离
    */
    template <class InputIterator>
    inline iterator_traits<InputIterator>::difference_type
    __distance(InputIterator first, InputIterator last, input_iterator_tag)
    {
    iterator_traits<InputIterator>::difference_type n = 0;
    while (first != last) {
    ++first; ++n;
    }
    return n;
    }
    /**
    * 针对random_access_iterator,可直接相减来计算差距
    */
    template <class RandomAccessIterator>
    inline iterator_traits<RandomAccessIterator>::difference_type
    __distance(RandomAccessIterator first, RandomAccessIterator last,
    random_access_iterator_tag)
    {
    return last - first;
    }
    // 入口函数,先判断迭代器类型iterator_category,然后调用特定函数
    template <class InputIterator>
    inline iterator_traits<InputIterator>::difference_type
    distance(InputIterator first, InputIterator last)
    {
    typedef typename iterator_traits<InputIterator>::iterator_category category;<*******
    return __distance(first, last, category());//这里的category()是构造勒一个*************^
    }

STL 所需之规范为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class _Category,
class _Ty,
class _Diff = ptrdiff_t,
class _Pointer = _Ty *,
class _Reference = _Ty&>
struct iterator
{ // base type for iterator classes
typedef _Category iterator_category;
typedef _Ty value_type;
typedef _Diff difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};

所以实现一个迭代器

1
2
3
4
template<class Item>
class ItemIter:
public std::iterator<std::forward_iterator_tag,Item>
{...};

Advance函数
Advance函数有两个参数,迭代器p和n,函数内部将p前进n次。针对不同类型的迭代器有如下实现:

  • 针对input_iterator和forward_iterator,单向,逐一前进
  • 针对bidirectional_iterator,双向,可以前进和后退,n>0和n<0
  • 针对random_access_iterator,支持p+n,可直接计算
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    /**
    * 针对input_iterator和forward_iterator版本
    */
    template <class InputIterator, class Distance>
    inline void __advance(InputIterator& i, Distance n, input_iterator_tag)
    {
    while (n--) ++i;
    }
    /**
    * 针对bidirectional_iterator版本
    */
    template <class BidirectionalIterator, class Distance>
    inline void __advance(BidirectionalIterator& i, Distance n,
    bidirectional_iterator_tag)
    {
    if (n >= 0)
    while (n--) ++i;
    else
    while (n++) --i;
    }
    /**
    * 针对random_access_iterator版本
    */
    template <class RandomAccessIterator, class Distance>
    inline void __advance(RandomAccessIterator& i, Distance n,
    random_access_iterator_tag)
    {
    i += n;
    }
    /**
    * 入口函数,先判断迭代器的类型
    */
    template <class InputIterator, class Distance>
    inline void advance(InputIterator& i, Distance n)
    {
    //第三个参数迭代器类型由traits机制得到
    __advance(i, n, iterator_traits<InputIterator>::iterator_category());
    }

Type_traits机制

iterator_traits负责萃取迭代器的特性;type_traits负责萃取型别的特性。

需要根据对象构造函数和析构函数的trivial和non-trivial特性来采用最有效的措施,例如:如果构造函数是trivial的,那么可以直接采用如malloc()和memcpy()等函数,来提高效率。

例如:如果拷贝一个未知类型的数组,如果其具有trivial拷贝构造函数,那么可以直接利用memcpy()来拷贝,反之则要调用该类型的拷贝构造函数。
type_traits的源代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/**
* 用来标识真/假对象,利用type_traits响应结果来进行参数推导,
* 而编译器只有面对class object形式的参数才会做参数推导,
* 这两个空白class不会带来额外负担
*/
struct __true_type{};
struct __false_type{};
/**
* type_traits结构体设计
*/
template <class type>
struct __type_traits
{
// 不要移除这个成员
// 它通知能自动特化__type_traits的编译器, 现在这个__type_traits template是特化的
// 这是为了确保万一编译器使用了__type_traits而与此处无任何关联的模板时
// 一切也能顺利运作
typedef __true_type this_dummy_member_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;
};
// 特化类型:
// char, signed char, unsigned char,
// short, unsigned short
// int, unsigned int
// long, unsigned long
// float, double, long double
/**
* 以下针对C++内置的基本数据类型提供特化版本,
* 使其具有trivial default constructor,
* copy constructor, assignment operator, destructor并标记其为POD类型
*/
__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;
};
//针对char的特化版本
__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;
};
//针对unsigned char的特化版本
__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;
};
//针对short的特化版本
__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;
};
//针对unsigned short的特化版本
__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;
};
//针对int的特化版本
__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;
};
//针对unsigned int的特化版本
__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;
};
//针对long的特化版本
__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;
};
//针对unsigned long的特化版本
__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;
};
//针对float的特化版本
__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;
};
//针对double的特化版本
__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;
};
//针对long double的特化版本
__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;
};
// 针对指针提供特化
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;
};
// 针对char *, signed char *, unsigned char *提供特化
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 把所有的内嵌型别都设置为__false_type,都给出最保守的值,再针对每个标量给出适当的特化版本

什么时候该有自己的non_trivial default constructor 等等。。。
如果class 内含有指针成员,并且对其进行了内存动态配置,那么这个class 就要实现自己的non-trivial-xxx