STL中的模板编程

模板编程入门

最近在阅读STL源码,源码里大量使用了模板编程,搞得好晕,在此梳理一下模板编程的基础用法
模板编程分为函数模板和类模板

函数模板

定义一个模板函数:

1
2
3
4
template <模板参数列表>
返回类型 函数名(函数参数列表) {
//code ...
}

例如: 下面这段代码可以计算任意容器内的元素之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename Container, typename Value>
Value sum(const Container& c, Value v)
{
for (auto x : c)
v += x;
return v;
}
void user(Vector<int>& vi, std::list<double>& ld, std::vector<complex<double>>& vc)
{
int x = sum(vi,0); //求整数向量的和(累加整数)
double d = sum(vi, 0.0); //求整数向量的和(累加浮点数)
double dd = sum(ld,0.0); //求浮点数列表的和
auto z = sum(vc, complex<double>{}); //求complex<double>向量的和,初始值是{0.0,0.0}
}

类模板

类模板主要应用于容器类中,使得容器能够处理各种类型的对象
定义一个模板类:

1
2
3
4
5
template <typename T>
Class 类名
{
//code ...
}

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T> //指明T是该声明的形参,它是数学上“对所有T”或“对所有类型T”的C++表达
class Vector {
private:
T* elem; //elem指向含有sz个T型元素的数组
int sz;
public:
Vector(int s); //构造函数:建立不等式,获取内存资源
~Vector() {delete[] elem;} //析构函数:释放资源
//拷贝和移动操作
T& operator[](int i);
const T& operator[](int i) const;
int size() {return sz;}
};

成员函数的定义与之类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
Vector<T>::Vector(int s)
{
if (s < 0)
throw Negative_size{};
elem = new T[s];
sz = s;
}
template <typename T>
const T& Vector<T>::operator[](int i) const {
if (i < 0 || size() < i)
throw out_of_range {"Vector::operator[]"};
return elem[i];
}

STL中的迭代器实现(smart pointer)

迭代器是一种行为类似指针的对象,指针的各种行为中最常见最重要的是内容提领(dereference)和成员访问(member access),因此,迭代器最重要的工作,就是对operator*和operator->进行重载(overloading)工作。关于这一点,C++标准程序库里有一个auto_ptr可供参考,这是一个用来包装原生指针(native pointer)的对象,可以有效解决内存泄露问题。
先说auto_ptr的用法:

1
2
3
4
5
6
7
8
9
10
include <memory>
void func() {
//用new动态配置一个初值为"hello world!"的string对象,并将所得结果作为auto_ptr<string>的初值
//注意:auto_ptr角括号内放的是“原生指针所指对象”的型别,而不是原生指针的型别!
auto_ptr<string> ps(new string("hello world!"));
cout << *ps << endl;
cout << ps->size() << endl;
//离开前不需要delete,auto_ptr会自动释放内存
}

auto_ptr的源码在头文件memory中,根据它可以简化成如下代码,可以具体说明auto_ptr的行为和能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template<class T>
class auto_ptr {
public:
explicit auto_ptr(T *p = 0) : pointee(p) {}
template<class U>
auto_ptr(auto_ptr<U>& rhs) : pointee(rhs.release()) {}
~auto_ptr() {delete pointee;}
template<class U>
auto_ptr<T>& operator=(auto_ptr<U>& rhs) {
if (this != &rhs)
reset(rhs.release());
return *this;
}
T& operator*() const {return *pointee;}
T* operator->() const {return pointee;}
T* get() const {return pointee;}
private:
T* pointee;
};

memory中的代码如下

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
template<class T>
class auto_ptr
{
private:
T *ap;
public:
//constructor & destructor-----------------------------------(1)
explicit auto_ptr(T*ptr=0)throw():ap(ptr) //构造函数
{
}
~auto_ptr()throw() //析构函数
{
delete ap;
}
//Copy & assignment--------------------------------------------(2)
auto_ptr(auto_ptr& rhs)throw():ap(rhs.release())
{
}
template<class Y>
auto_ptr(auto_ptr<Y>&rhs)throw():ap(rhs.release())
{
}
auto_ptr& operator=(auto_ptr&rhs)throw()
{
reset(rhs.release());
return *this;
}
template<class Y>
auto_ptr& operator=(auto_ptr<Y>&rhs)throw()
{
reset(rhs.release());
return *this;
}
//Dereference----------------------------------------------------(3)
T& operator*()const throw()
{
return *ap;
}
T* operator->()const throw()
{
return ap;
}
//Helper functions------------------------------------------------(4)
//value access
T* get()const throw()
{
return ap;
}
//release owner ship
T* release()throw()
{
T*tmp(ap);
ap=0;
return tmp;
}
//reset value
void reset(T*ptr=0)throw()
{
if(ap!=ptr)
{
delete ap;
ap=ptr;
}
}
//Special conversions-----------------------------------------------(5)
template<class Y>
struct auto_ptr_ref
{
Y*yp;
auto_ptr_ref(Y*rhs):yp(rhs){}
};
auto_ptr(auto_ptr_ref<T>rhs)throw():ap(rhs.yp)
{
}
auto_ptr& operator=(auto_ptr_ref<T>rhs)throw()
{
reset(rhs.yp);
return *this;
}
template<class Y>
operator auto_ptr_ref<Y>()throw()
{
return auto_ptr_ref<Y>(release());
}
template<class Y>
operator auto_ptr<Y>()throw()
{
return auto_ptr<Y>(release());
}
};

坚持原创技术分享,您的支持将鼓励我继续创作!