static变量在不同的对象
#include<iostream>
using namespace std;
template <typename T>
class Test{
public:
static int _data;
int a;
};
template<>int Test<int>::_data = 1;
template<>int Test<char>::_data = 2;
//static变量是属于整个类,而不是某个对象
int main()
{
cout<<Test<int>::_data<<endl;//1
cout<<Test<char>::_data<<endl;//2
Test<int> obji1,obji2;
Test<char> objc1,objc2;
cout<<obji1._data<<endl;//1
cout<<obji2._data<<endl;//1
cout<<objc1._data<<endl;//2
cout<<objc2._data<<endl;//2
obji1._data = 3;//_data = 3共同属于obji1和obji2对象
objc2._data = 4;
cout<<obji1._data<<endl;//3
cout<<obji2._data<<endl;//3
cout<<objc1._data<<endl;//4
cout<<objc2._data<<endl;//4
obji1.a = 222;//a = 222是属于obji1这个对象的,不属于obji2对象
cout<<obji1.a<<endl;//222
cout<<obji2.a<<endl;//随机
}
STL中的迭代器
template<class T>
class List{
public:
void insert_front(T value);
void insert_end(T value);
void display() const();
ListItem<T>* begin() const
{
return _front;
}
typedef ListIter<ListItem<T>> iterator;//所以说迭代器是一个对象,是一个行为类似指针的对象。和智能指针一样,是个对象。
private:
ListItem<T>* _end;
ListItem<T>* _front;
long _size;
};
template<class T>
class ListItem{
public:
T value() const
{
return _value;
}
ListItem* next() const
{
return _next;
}
private:
T _value;
ListItem<T>* _next;
};
template<class Item>
struct ListIter
{
Item* ptr;
ListIter(Item* p = NULL):ptr(p){}
Item& operator *() const
{
return *ptr;
}
Item* operator ->() const
{
return ptr;
}
ListIter& operator ++()
{
ptr = ptr->next();
return *this;
}
ListIter& operator ++(int)
{
ListIter tmp = *this;
++(*this);
return temp;
}
bool operator ==(const ListIter &i) const
{
return ptr == i.ptr;
}
bool operator !=(const ListIter &i) const
{
return ptr != i.ptr;
}
};
void main()
{
List<int> myList;
for(int i = 0;i < 5;++i)
{
myList.insert_front(i);
myList.insert_end(i+2);
}
list<int>::iterator pd;
pd = myList.begin();
}
类模板中可以再有一个模板函数(class template中可以再有template(menbers))
#include<iostream>
using namespace std;
class alloc{
};
//迭代器的定义方法,其实迭代器是一个T类型的指针 vector<int>::iterator pd. pd就是一个int类型的指针。
template<class T,class Alloc = alloc>
class vector{
public:
typedef T value_type;
typedef value_type* iterator;
template<class I>
void insert(iterator position,I first,I last)
{
cout<<"insert()"<<endl;
}
};
int main()
{
int ia[5] = {0,1,2,3,4};
vector<int> x;
vector<int>::iterator ite;
x.insert(ite,ia,ia+5);
}
template参数可以根据前一个template参数设定默认值
#include<iostream>
using namespace std;
class alloc{
};
template<class T,class Alloc = alloc,size_t BufSiz = 0>
class deque{
public:
deque(){cout<<"deque"<<endl;}
};
template<class T,class Sequence = deque<T>>//相当于template<class T,class Sequence = deque<T,alloc,0>>
class stack{
public:
stack(){cout<<"stack"<<endl;}
private:
Sequence c;
};
int main()
{
stack<int> x;//输出 deque和stack
}
临时对象的产生于运用
template<class T>
class print{
public:
void operator()(const T &elem)//注意若是重载运算符(),函数定义为 print operator()(const T &elem)
{
cout<<elem<<' ';
}
};
template<class T>
static void out(T n)
{
cout<<n<<" ";
}
int main()
{
int ia[6] = {0,1,2,3,4,5};
vector<int> iv(ia,ia+6);
//print<int>(iv.begin());//调用失败
for_each(iv.begin(),iv.end(),print<int>());//print<int>()是一个临时对象,不是一个函数调用操作
for_each(iv.begin(),iv.end(),out<int>);//平时都是使用这种方式调用。
}
STL空间配置器
在程序设计中,我们不免因为程序需求,使用很多的小块内存(基本类型以及小内存的自定义类型)。在程序中动态申请,释放。这个过程过程并不是一定能够控制好的,于是乎,
问题1:就出现了内存碎片问题。(ps外碎片问题)
问题2:一直在因为小块内存而进行内存申请,调用malloc,系统调用产生性能问题。
注:内碎片:因为内存对齐/访问效率(CPU取址次数)而产生 如 用户需要3字节,实际得到4或者8字节的问题,其中的碎片是浪费掉的。
外碎片:系统中内存总量足够,但是不连续,所以无法分配给用户使用而产生的浪费。
这两个问题解释清楚之后,就来谈STL空间配置器的实现细节了
实现策略
用户申请空间大于128B?
yes:调用一级空间配置器
no:调用二级空间配置器
大致实现为:
二级空间配置由内存池以及伙伴系统:自由链表组成
一级空间配置器直接封装malloc,free进行处理,增加了C++中的set_handler机制(这里其实也就是个略显牵强的装饰/适配模式了),增加内存分配时客户端可选处理机制。
void MyOutOfMemory()
{
cout << "Out of memory error!" << endl;
abort();
}
int main()
{
set_new_handler(MyOutOfMemory);
int *verybigmemory = new int[0x1fffffff];//不能正常分配内存的时候,调用MyOutOfMemory函数
delete verybigmemory;
}
可配置性:
客户端可以通过宏__USE_MALLOC进行自定义选择是否使用二级空间配置器。
一级空间配置器就主要封装malloc,添加handler机制了,这里就不罗嗦了,相信各位都是可以通过源码了解到的
[图片上传失败...(image-8506b-1560669207937)]

偏特化和萃取
template<class T>
struct iterator_traites{
typedef T value_type;
};
template<class T>
struct iterator_traites<T *>{
typedef T value_type;
};
template<class T>
struct iterator_traites<const T *>{
typedef T value_type;
};
template<class T>
struct TraitsHelper{//注意这是一个普通的类模板
static const bool isPointer = false;
};
template<class T>
struct TraitsHelper<T*>{
static const bool isPointer = true;
};
template <typename T>
class Test {
public:
typedef typename iterator_traites<T>::value_type iv;
iv Compute()
{
if(TraitsHelper<T>::isPointer)
cout<<"is pointer"<<endl;
else
cout<<"not pointer"<<endl;
iv k;//如果传进来的是指针,那么k就是一个指针,如果传进来的是普通类型,那么k就是普通类型。
return k;
}
private:
T mData;
};
int main()
{
Test<int *> t1;
cout<<t1.Compute()<<endl;
}
STL中的配接器adapter
配接器(适配器)也是一种设计模式,在C++1中和单例模式都有介绍,是对某种方法的再封装改造。官方解释为:将一个 class 的接口转换为另一个 class 的接口,使原本因接口不兼容而不能合作的 classes,可以一起运作。一言以蔽之,Adapter 用于改变接口。
STL提供了三种适配器:
1.改变容器接口,称之为container adapter
2.改变迭代器接口,称之为iterator adapter
3.改变仿函数接口,称之为function adapter
应用于容器:queue和stack严格意义上来说是配接器而不是容器,因为queue和stack是对deque的再封装(接口的改造)。
set和map(序列式容器)是对红黑树的再封装(接口的改造)。
应用于迭代器:
(1)insert iterators(2)reverse iterators(3)iostream iterators istream_iterator ostream_iterator
所谓 insert iterators,可以将一般迭代器的赋值(=,assign)操作变为插入(insert)操作。这样的迭代器包括专司尾端插入操作back_insert_iterator,专司头端插入的 front_insert_iterator,以及可在任意位置执行插入操作的 insert_iterator。由于这三个 iterator adapters 的使用接口不太直观,给一般用户带来困扰,STL 提供三个相应函数,back_inserter_iterator()、front_inserter_iterator()、inserter_iterator()
template <typename Container>
class BackInsertIterator
{
public:
typedef typename Container::value_type value_type;
explicit BackInsertIterator(Container &cont)//类属性是一个容器,这个类就是对这个容器操作
:_cont(cont)
{ }
BackInsertIterator<Container> &operator= (const value_type &val)
{
_cont.insert(_cont.end(), val);//其实还是调用了容器的插入操作(再封装)
return *this;
}
BackInsertIterator<Container> &operator*()
{ return *this; }
BackInsertIterator<Container> &operator++()
{ return *this; }
BackInsertIterator<Container> &operator++(int)
{ return *this; }
private:
Container &_cont;
};
在使用的时候:
int main()
{
char a[6]={'a','b','c','d','f','g'};
vector <char> b(6);
b.push_back('k');b.push_back('m');
copy(a,a+4,back_insert_iterator< vector<char> >(b));
for(int i = 0;i < b.size();++i)
cout<<b[i]<<" ";
return 0;
}
应用于仿函数:
functor adapters(亦称为 function adapters)是所有配接器中数量最为庞大的一个族群,其配接灵活程度也非前二者所能及,可以配接、配接、再配接。这些配接操作包括,
(1)系结(bind)、否定(negate)、组合(compose),
(2)以及对一般函数或成员函数的修饰(使其成为一个仿函数)