STL

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)]

image.png

偏特化和萃取

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)以及对一般函数或成员函数的修饰(使其成为一个仿函数)


©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容