c++STL
容器
课程中使用了 gcc 2.9,旧版本中继承关系更少,代码更简洁。更容易阅读,且原理相同
- 
容器 Containers 序列容器 Sequence Containers Array 
 Vector 尾端可扩充的数组
 Deque 双端可扩充的数组
 List 双向队列
 Forward-List 单向队列关联容器 Associative Containers 通过红黑树实现的有序容器 Set key不可重复 
 Multiset key可重复
 Map
 Multimap无序容器 Unordered Containers 哈希表实现的容器,使用拉链法 Unordered Set Multiset 
 Unordered Map Multimap
- 
分配器 Allocators 
- 
算法 Algorithms 
- 
迭代器 Iterators 
- 
适配器 Adapters 
- 
仿函数 Functors 
int ia[6] = {1,2,3,4,5,6};
vector<int, allocator<int>> vi(ia, ia+6); // vector的第二个参数是空间分配器
count << count_if(vi.begin(), vi.end(), 
                  not1(bind2nd(less<int>(), 40)));//统计大于等于40的个数
STL中使用“左闭后开”表示数据范围。c.begin()表示第一个元素,c.end()表示最后一个元素后面的位置。
Container<T>::iterator c;
for (auto c = vec.begin; c != vec.end(); ++c);
for (auto& c : vec);
分配器
每个容器有个默认分配器,可以在尖括号内指定。分配器底层还是调用了malloc
// vector 的定义,可见模板参数中有指定内存分配器的参数,且此参数有默认值
template <typename _Tp, typename _Alloc=std::allocator<_Tp>>
  class vector : protected _Vector_base<_Tp, _Alloc>
gcc 下的拓展分配器,不同编译器下不同。
#ifdef __GNUC__		
#include <ext\array_allocator.h>
#include <ext\mt_allocator.h>
#include <ext\debug_allocator.h>
#include <ext\pool_allocator.h>
#include <ext\bitmap_allocator.h>
#include <ext\malloc_allocator.h>
#include <ext\new_allocator.h>  
#endif
void fun() {
    // 其定义在非std命名空间
    list<string, __gnu_cxx::malloc_allocator<string>> c2;  	//3110
    list<string, __gnu_cxx::new_allocator<string>> c3; 		//3156
    list<string, __gnu_cxx::__pool_alloc<string>> c4;  		//4922
    list<string, __gnu_cxx::__mt_alloc<string>> c5; 		//3297
    list<string, __gnu_cxx::bitmap_allocator<string>> c6;  	//4781 	
    
    // 分配器也是一个类,可以直接使用。其只有allocate和deallocate两个方法。一般没必要使用,而是使用new delete malloc free
	int* p; 	
    allocator<int> alloc1;	
	p = alloc1.allocate(1);  
	alloc1.deallocate(p,1); 	
						
	__gnu_cxx::malloc_allocator<int> alloc2;  
	p = alloc2.allocate(1);  
	alloc2.deallocate(p,1);  	
		
    __gnu_cxx::new_allocator<int> alloc3; 	
	p = alloc3.allocate(1);  
	alloc3.deallocate(p,1); 	
		
	__gnu_cxx::__pool_alloc<int> alloc4;  	
	p = alloc4.allocate(2);  // 分配两个int大小的空间
	alloc4.deallocate(p,2);  // 释放两个int大小的空间,释放空间时与free delete不同,需要指定大小
		
	__gnu_cxx::__mt_alloc<int> alloc5; 	
	p = alloc5.allocate(1);  
	alloc5.deallocate(p,1);  	
			
    __gnu_cxx::bitmap_allocator<int> alloc6;  	
	p = alloc6.allocate(3);  
	alloc6.deallocate(p,3);
}
OOP 面向对象编程 与 GP 泛型编程
OOP将data与methods包装在一起,GP则是将二者分开。
OOP
所有工作都由类开发者完成
class Class<typename T> {
    ...
    T min(const T& a, const T& b) {
        return a < b ? a : b;
    }
}
GP
容器团队与算法团队可以分工合作
class Class<typename T> {}
template<typename _Tp> 
const _Tp& min(const _Tp& __a, const _Tp& __b) {}
list 的 sort 方法
一般容器在排序时都使用全局排序方法 ::sort() ,而双向队列 list 的排序方法在自己内部定义。
全局排序方法中需要对指针或泛化指针进行加减乘除等操作,这就要求是随机指针,而list是双向链表。
以下都是 gcc2.9 版本的源代码
lists
在尾端多添加了一个空白节点,以实现“左闭右开”区间。底层是一个循环双向链表。
template<typename _Tp, typename _Alloc = alloc >
class list {
protected:
    typedef __list_node<T> list_node; // node节点
public:
    typedef list_node* link_type;
    typedef __list_iterator<T, T&, T*> iterator; // 迭代器本质上是一个指针
protected:
    link_type node; // 指向节点的指针,2.9版本占4字节
                    // 4.9版本占8字节,因为其父类拥有一个链表节点__List_node_base,其包含了两个指针
// ...
};
template <class T>
struct __list_node {
    typedef void* void_pointer;
    void_pointer prev; // 指向前后的指针,没增加一个元素都会多占用的空间
    void_pointer next; // 在4.9中不再使用void*
    T data;
};
template<class T, class Ref, class Ptr> //   新版中只传入一个参数 T
struct __list_iterator { // 类似指针的类
    typedef __list_iterator<T, Ref, Ptr> self;
    typedef __list_node<T>* link_type;
    
    /*每个容器的 iterator 都一定要有以下5个 typedef*/
    typedef bidirectional_iterator_tag iterator_category; // 迭代器的种类:只能向前/可以后退/每次只能加1/每次可以增加大于1的值
    typedef T   value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef ptrdiff_t difference_type; // 表示两个元素的距离的变量类型 unsigned int/
    
    link_type node;
// ...
    reference operator*() const { 
        return (*node).data;
    }
    pointer operator->() const { 
        return &(operator*()); 
    }
    self& operator++() { // ++i
        node = (link_type) ((*node).next);
        return *this;
    }
    self operator++(int) { // i++
        // 此处调用copy ctor用于创建tmp,并以*this为初值,不会唤起operator*操作符
        // 因为*this已被解释为ctor的参数
        self tmp = *this;
        ++*this; // 使用到了已重载的 operator++()
        return tmp;
    }
    __list_iterator(const iterator& x) : node(x.node) {}
// ...
};
vector
  |+++++++++++++++++++++++++++|----------------|
start                         finish    end_of_storage
  <-----------size------------>
  <------------------capacity------------------>
当空间使用完时申请一个2倍大小的空间,然后将旧数据复制过去  
template <class T, class Alloc = alloc>
class vector {
public:
    typedef T           value_type;
    typedef value_type* iterator_pointer; // 直接将 native pointer 当作迭代器
    typedef value_type& iterator_reference;
    typedef size_t      size_type;
protected:
    // 容器vector的大小就是这三个指针的大小,为12或24
    iterator start;
    iterator finish;
    iterator end_of_storage;
public:
    iterator begin() { return start; }
    iterator end() {return finish; }
    size_type size() const {
        return size_type(end() - begin());
    }
    size_type capacity() const {
        return size_type(end_of_storage - begin());
    }
    bool empty() const { return begin() == end(); }
    reference operator[](size_type n) { return *(begin() + n); }
    reference front() { return *begin(); }
    reference back() { return *(end() - 1); }
   
    void push_back(const T& x) {
        if (finish != end_of_storage) {
            // 当空间充足时向 finish 位置加入元素
            construct(finish, x);
            ++finish;
        }
        else
            // 空间不足时申请双倍空间在添入元素
            insert_aux(end(), x);
    }
    
    template <class T, class Alloc>
    void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
        if (finish != end_of_storage) {
            // 与vector中操作类似,因为这个方法不仅仅被某一个容器调用
            construct(finish, x);
            ++finish;
            T x_copy = x;
            copy_backward(position, finish - 2, finish - 1);
            *position = x_copy;
        }
        else {
            const size_type old_size = size();
            const size_type len = old_size != 0 ? 2 * old_size : 1;
            
            iterator new_start = data_allocator::allocate(len);
            iterator new_finish = new_start;
            // 复制元素,期间涉及每个元素的拷贝构造函数与析构函数,空间的销毁
            try {
                
            } catch () {
                
            }
            destory(begin(), end());
            deallocate();
            start = new_start;
            finish = new_finish;
            end_of_storage = new_start + len;
        }
    }
    
      void
      push_back(const value_type& __x)
      {
	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
	  {
	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x);
	    ++this->_M_impl._M_finish;
	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
	  }
	else
	  _M_realloc_insert(end(), __x);
      }
};
 
array
将一个数组包装成类,然后它就遵循一定的规则,需要提供迭代器、特殊成员变量等,也可以适应算法库。
template <typename _Tp, std::size_t _Nm>
struct array {
    typedef _Tp          value_type;
    typedef _Tp*         pointer;
    typedef value_type*  iterator;
    
    value_type _M_instance[_Nm ? _Nm : 1];//没有 ctor dtor
    
    iterator begin() { return iterator(&_M_instance[0]); }
    
    iterator end() { return iterator(&_M_instance[_Nm]); }
};
forward_list
线性单项链表
deque
使用了分段存储的思想,一个大数组元素是各个子数组,也称buffer。具体数据存储在buffer中。
每次扩充时新建一个buffer并插入到父数组中,当父数组空间不足时父数组也扩容。
子数组大小不变,扩容阔的是父数组,父数组为vector。
每次扩容时将旧数据复制到数组的中段,为的是左右端都有相同空间。
   |------|------|------|------|      |      | => 增长方向
   |      |      |      |1|2|3|4|5|6|7|8|9| |
   |      |      |1|2|3|4|5|6|7|8|9|10|   |
   |      |1|2|3|4|5|6|7|8|9|10|         finish[end()返回的尾指针]指向此处
   | | | |4|5|6|7|8|9|10|
         |
       start[begin()返回的头指针]指向此处
iterator包含4个元素
    cur   指向当前元素
    first 指向当前buffer中第一个元素
    last  指向当前buffer中最后一个元素
    node  指向父数组中的当前节点
template <class T, class Alloc = alloc, size_t BufSiz = 0>//旧版本可以指定buffer大小,新版不可以
class deque {
public:
    typedef T value_type;
    typedef __deque_iterator<T> iterator;
protected:
    typedef prointer* map_pointer; // T**
    iterator start;
    iterator finish;
    map_pointer map;
    size_type map_size;
public:
    iterator begin() {return start;}
    iterator end() {return finish;}
    size_type size const {return finish - start;}
    
    iterator insert(iterator position, const value_type& x) {
        if (position.cur == start.cur) {//插到最前端交给 push_front 做
            push_front(x);
            return start;
        } else if (position.cur == finish.cur) {//插到最后段交给 push_back 做
            push_back(x);
            iterator tmp = finish;
            --tmp;
            return tmp;
        } else {
            return insert_aux(position, x);
        }
    }
    
    template <class T, class Alloc, size_t BufSize>
    typename deque<T, Alloc, BufSize>::iterator
    deque<T, Alloc, BufSize>::insert_aux(iterator pos, const value_type& x) {
        differenct_type index = pos - start; // 安插点之前的元素个数
        value_type x_copy = x;
        if (index < size() / 2) { // 如果安插点之前的元素较少
            push_front(front());  // 在最前端加入与第一个元素相同的元素
            // ...
            copy(front2, pos1, font1); // 元素搬移
        } else {                       // 如果安插点之后的元素较少
            push_back(back());         // 在最后端加入与最后一个元素相同的元素
            // ...
            copy_backward(pos, back2, back1); // 元素搬移
        }
        *pos = x_copy; // 安插点设置新值
        return pos;
    }
/******************   如何模拟连续空间? 依靠迭代器,对操作符进行了重载  **********************/
    reference operator[](size_type n) {
        return start[difference_type(n)];
    }
    reference front() { return *start; }
    reference back() {
        iterator tmp = finish;
        --tmp;
        return *tmp;
    }
    size_type size() const { return finish - start; }
    bool empty() const { return finish == start; }
// ...
};
template <class T>
struct __deque_iterator {
    typedef random_access_iterator_tag iterator_category; 
    typedef T   value_type;
    typedef T*  pointer;
    typedef T&  reference;
    typedef ptrdiff_t difference_type;
    
    typedef size_t size_type;
    typedef T** map_potinter;
    typedef __deque_iterator self;
    
    // 迭代器大小为 16 或 32
    T* cur;
    T* first;
    T* last;
    map_pointer node;
    
    reference operator*() const {
        return *cur;
    }
    pointer operator->() const {
        return &(operator*());
    }
    difference_type
    operator-(const self& x) const {
        return difference_type(buffer_size()) * (node - x.node - 1) +//buffer_size函数用于获取buffer大小
            (cur - first) + (x.last - x.cur);
        // 当前buffer的元素量    被减数buffer元素量
    }
    self& operator++() {
        ++cur;
        if (cur == last) {
            set_node(node + 1);
            cur = first;
        }
        return *this;
    }
    self operator++() {
        self tmp = *this;
        ++*this;
        return tmp;
    }
    // 切换到父数组中下一个元素
    void set_node(map_pointer new_node) {
        node = new_node;
        first = *new_node;
        last = first + difference_type(buffer_size());
    }
    self& operator--() {
        if (cur == first) {
            set_node(node - 1);
            cur = last;
        }
        --cur;
        return *this;
    }
    self operator--(int) {
        self tmp = *this;
        --*this;
        return tmp;
    }
    self& operator+=(difference_type n) {
        difference_type offset = n + (cur - first);
        if (offset >= 0 && offset < difference_type(buffer_size())) {
            cur += n;
        } else {
            difference_type node_offset = 
                offset > 0 ? 
                offset / difference_type(buffer_size()) 
                : -differnece_type((-offset - 1) / buffer_size() - 1);
            set_node(node + node_offset);
            cur = first + (offset - node_offset * difference_type(buffer_size()));
        }
        return *this;
    }
    self operator+(difference_type n) const {
        self tmp = *this;
        return tmp += n;
    }
// ...
};
queue stack
内部包含一个deque,用自己的队列 / 栈方法封装对deque的操作。
都不允许遍历,也不提供 iterator。
都可以选择使用list作为底层结构。
queue不可选择vector当作底层结构,stack可选择vector当底层结构。
Iterator 的设计原则
迭代器作为算法与容器间的桥梁。
template<typename _Tp>
struct _List_iterator {
    /**
     * 每个容器的 iterator 都一定要有以下5个 typedef
     */
    // 迭代器的种类:只能向前/可以后退/每次只能加1/每次可以增加大于1的值
    // bidirectional_iterator_tag 代表可以双向迭代
    typedef bidirectional_iterator_tag iterator_category; 
    typedef T   value_type;
    typedef T*  pointer;
    typedef T&  reference;
    typedef ptrdiff_t difference_type; // 表示两个元素的距离的变量类型 unsigned int 等
};
template<typename I>
inline void
algorithm(I first, I last) {
    // 在算法中会直接使用以上的5中自定义类型
    I::iterator_category;
    I::pointer;
    I::reference;
    I::value_type;
    I::difference_type;
}
iterator traits 迭代器萃取机
/*
算法库不仅可以作用于 class pointer(泛化的指针) 还可以作用于 native pointer(退化的迭代器)
使用 iterator traits 进行分辨:这个traits必须有能力分辨 iterator 是 class iterator T 还是 native pointer to T
利用 partial specialization 可以达到目标
*/
template <class T>
struct iterator_traits { // I 为 class iterator
    typedef typename I::iterator_category iterator_category;
    typedef typename I::value_type        value_type;
    typedef typename I::difference_type   difference_type;
    typedef typename I::pointer           pointer;
    typedef typename I::reference         reference;
};
// 利用 partial specialization 
template <class T>
struct iterator_traits<T*> { // I 为 pointer to 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*> { // I 为 pointer to const T
    typedef random_access_iterator_tag iterator_category;
    typedef T                          value_type;// 注意不是 const T,这里加上const后无法初始化赋值
    typedef ptrdiff_t                  difference_type;
    typedef T*                         pointer;
    typedef T&                         reference;
};
template<typename I, ...>
void algorithm(...) {
    // 算法获取I的value type时可使用这种方法
    typename iterator_traits<I>::value_type v1;
}
RB_tree 红黑树
C++中rb-tree 可以使用迭代器改变元素的值,但不应用其改变key的值,使用场景是在map结构中改变value的值。rb-tree提供两种insert操作:1. insert_unique() key不可以重复 2. insert_equal() key可以重复
begin() 返回指向最左下角的元素的迭代器,end() 返回指向最右下角的元素的迭代器。在root节点之前有一个header指针指向的一个哑节点,这个节点还指向 begin() end()
template <class Key, 
          class Value, // 键值对合并后的数据
          class KeyOfValue,  // 如何从键值对中拿到key
          class Compare, 
          class Alloc=alloc>
class rb_tree {
protected:
    typedef __rb_tree_node<Value> rb_tree_node;
    ...
public:
    typedef rb_tree_node* link_type;
    ...
protected:
    size_type node_count; // rb_tree的大小 节点个数
    link_type header;
    Compare key_compare; // 模板参数,一个 function object
    ...
};
// 使用方法
rb_tree<int, 
        int, // 意味着只有键没有值
        identity<int>,  // 这个identity是gcc独有的
        less<int>, 
        alloc> myTree;
template<class T>
struct identity : public unary_function<T, T> {
    const T& operator() (const T& x) const {
        return x;
    }
};
template<class T>
struct less : public binary_function<T, T, bool> {
    bool operator() (const T& x, const T& y) const {
        return x < y;
    }
};

set multiset
无法使用迭代器改变元素值,set multiset的迭代器底部就是RBtree的 const iterator,就是禁止对元素赋值。
set使用 insert_uniqui(); multiset 使用 inert_equal()
set map 都是一种 container adapter。
template <class Key,
          class Compare = less<Key>,
          class Alloc = alloc>
class set {
public:
    typedef Key key_type;
    typedef Key value_type;
    typedef Compare key_compare;
    typedef Compare value_compare;
private:
    typedef rb_tree<key_type, value_type, 
            identity<value_type>, key_compare, Alloc> rep_type;
    rep_type t; // 具体工作都调用rbtree实现
public:
    typedef typename rep_type::const_iterator iterator; // 此处迭代器不允许改变
    // ...
};
// 使用方法
set<int> iset;
// 等于
set<int, less<int>, alloc> iset;
// 底层使用
template<int, int, identity<int>, less<int>, alloc>
class rb_tree;
map multimap
与set类似,value包括key加data。
template <class Key, class T, 
          class Compare = less<Key>, class Alloc=alloc>
class map {
public:
    typedef Key key_type;
    typedef T data_type;
    typedef T mapped_type;
    typedef pair<const Key, T> value_type;// const Key 保证了key不可以改变
    typedef Compare key_compare;
private:
    typedef rb_tree<key_type, value_type, 
                    select1st<value_type>, // select1st与identify类似都是gcc独有的
                    key_compare, Alloc> rep_type;
    rep_type t;
public:
    typedef typename rep_type::iterator iterator;//map的迭代器就是红黑树的迭代器
    
    // 通过key取得data,如果key不存在则使用默认值创建键值对
    mapped_type& operator[] (const key_type& k) {
        // 二分查找获取位置,不存在时返回应该处于的位置
        iterator i = lower_bound(k);
        if (i == end() || key_comp()(k, (*i).first))
            i = insert(i, value_type(k, mapped_type()));
        return (*i).second;
    }
// ...
};
// 使用
map<int, string> imap;
map<int, string, less<int>, alloc> imap;
// 底层
template <int, pair<const int, string>, // const Key 保证了key不可以改变
         select1st<value_type>, less<int>, alloc>
         class rb_tree
hashtable
template <class Value, class Key, class HashFcn, // 哈希函数
          class ExtractKey, class EqualKey, class Alloc=alloc>
class hashtable {
public:
    typedef HashFcn hasher;
    typedef EqualKey key_equal;
    typedef size_t size_type;
private://三个函数对象(1*3) + 一个vector(4*3) + 元素总数(4) = 19,对齐调整为20
    hasher hash;
    key_equal equals;
    ExtractKey get_key;
    typedef __hashtable_node<Value> node;
    vector<node*, Alloc> buckets;
    size_type num_elements;
public:
    size_type bucket_count() const {
        return buckets.size();
    }
    
    template <class Value, class Key, class HashFcn, class ExtractKey, 
              class EqualKey, class Alloc=alloc>
    struct __hashtable_iterator {
        // ...
        node* cur;
        hashtable* ht;
    };
    
    template<class Value>
    struct __hashtable_node {
        __hashtable_node* next;
        Value val;
    };
// ...
};
// 使用
hashtable<const char*, const char*, hash<const char*>, // hash模板可能需要用户自己自定义偏特化场景
    identity<const char*>, eqstr, alloc>               // 标准库没有提供 hash<std::string>
    ht(50, hash<const char*>(), eqstr());
ht.insert_unique("kiwi");
// cstring使用strcmp判断是否相等但它返回-1 0 1,而不是bool,需要一层转换。
struct eqstr {
    bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) == 0;
    }
};
// 拓展出的 set unordered_set map unordered_multimap
template <typename T, 
          typename Hash = hash<T>, 
          typename EqPred = equal_to<T>, 
          typename Allocator = allocator<T>>
class unordered_set;
template <typenaem Key, typename T, 
          typename Hash = hash<T>, 
          typename EqPred = equal_to<T>, 
          typename Allocator = allocator<pair<cosnt Key, T>>>
class unordered_multimap;
写出对象的hash函数
当对用于hashtable的key时必须要有hash函数
template<>
struct hash<string>
    : public __hash_base<size_t, string>
{
	size_t operator()(const string& ...s) const noexcept {
        return std::Hash_impl::hash(__s.data(), __s.length());
    }
};
算法
是一种 function template,不会直接接触到容器,而是通过迭代器简介处理容器。只有迭代器满足算法的调用才能正常编译。
迭代器分类
使用 struct 表示不同的种类,而不是通过int类型。原因:1. 可以通过模板参数与偏特化进行高效的处理
- struct input_iterator_tag
- struct output_iterator_tag
- struct forward_iterator_tag : public input_iterator_tag
 Forward_List 单链表实现的 HashTable
- struct bidirectional_iterator_tag : public forward_iterator_tag
 List RB_tree 双链表实现的 HashTable
- struct random_access_iterator_tag : public bidirectional_iterator_tag
 Array Vector Deque
template<typename I>
void display(I itr) {
    cout << typeid(itr).name() << endl;
}
int main() {
    display(array<int, 3>::iterator());
    display(vector<int>::iterator());
    display(list<int>::iterator());
    display(forward_list<int>::iterator());
    display(deque<int>::iterator());
    display(set<int>::iterator());
    display(multiset<int>::iterator());
    display(map<int, int>::iterator());
    display(multimap<int, int>::iterator());
    // Pi
    // N9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
    // St14_List_iteratorIiE
    // St18_Fwd_list_iteratorIiE
    // St15_Deque_iteratorIiRiPiE
    // St23_Rb_tree_const_iteratorIiE
    // St23_Rb_tree_const_iteratorIiE
    // St17_Rb_tree_iteratorISt4pairIKiiEE
    // St17_Rb_tree_iteratorISt4pairIKiiEE
    exit(EXIT_SUCCESS);    
}
迭代器对算法的影响
判断处迭代器的分类,然后对于不同的迭代器进行不同的操作从而获得更高的效率。
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;
}
    
template<class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last, 
           random_access_iterator_tag) { // 获得迭代器种类
    return last - first; // 对于随机存取直接对指针进行相减
}
// 给其他算法库调用的算法,不直接暴露给用户
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());//不同情况调用不同的函数求差值
}
accumulate
template<class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init) {
    for (; first != last; ++first)
        init += *first;
    return init;
}
template<class InputIterator, class T, class BinaryOperator>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperator binary_op) {
    for (; first != last; ++first)
        init = binary_op(init, *first);
    return init;
}
// 符合 BinaryOperator 的可调用类
int fun(int x, int y) { return x + y; }
struct func {
    int operator()(int x, int y) { return x + y; }
} obj;
// obj 就可以作为可调用对象传递,称为 仿函数
for_each
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f) {
    for (; first != last; ++first)
        f(*first);
    return f;
}
仿函数 functor
注意:写出的functor必须要继承 binary_funcation 才可以正常用于库算法的运行。
- 
算术类 
- 
逻辑运算类 && || ~ 
- 
相对关系类 == < > template<class T> struct equal_to : public binary_funcation<T, T, bool> { bool operator()(const T& x, const T& y) { return x == y; } }
identity select1st select2nd 等都是gcc独有的非标准库函数。
Adapters 适配器
多种适配器,改造容器的叫 Container Adapters,改造迭代器的叫 Iterator Adapters,改造仿函数的叫 Functor Adaptors。把内容包装起来,让底层结构提供功能,适配器向外开放统一接口。
- 
迭代器适配器 
 针对 Iterator Adapterstypedef x1 iterator_category; typedef x2 value_type; typedef x3 pointer; typedef x4 reference; typedef x5 difference_type;
- 
仿函数适配器 
 针对 Functor Adaptorstypedef Arg argument_type; typedef Result result_type; typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type;
- 
容器适配器 
 stack queue
functors 可适配(adaptable)的条件
STL 规定每个 Adaptable Function 都应当挑选适当的类继承,Adapt 使用辅助函数中定义的类型别名声明变量进行操作:
/*      选择适当的一个继承     */
// 一个操作数的仿函数
template <class Arg, class Result>
struct unary_function {
    typedef Arg argument_type;
    typedef Result result_type;
};
// 两个参数的仿函数
template <class Arg1, class Arg2, class Result>
struct binary_function {
    typedef Arg1 first_argument_type;
    typedef Arg2 second_argument_type;
    typedef Result result_type;
};
FunctorAdapters函数适配器
function adaptor 通过继承 unary_function bunary_function 获得对于参数、返回值类型的重命名。
bind2nd() (被抛弃,使用 bind)
绑定一个函数或函数对象的第二个参数
/*
将类函数函数 less 绑定第二个参数 40
判断 40 是否合法的方式是将其强转为 `typedef typename Operation::second_argument_type arg2_type` 类型
*/
bind2nd(less<int>(), 40);
// 辅助函数,让用户方便使用 binder2nd<Op>,编译器自动推导Op的type
template <class Operation, class T>
inline binder2nd<Opertation> bind2nd(const Operation& op, const T& x) {
    // typename Operation::second_argument_type 要求 Operation 
    // 必须要有 second_argument_type 类型,即继承 bunary_function
    typedef typename Operation::second_argument_type arg2_type;
    //创建一个 binder2nd 对象,这是一个简化对象创建的方法
    return binder2nd<Operation>(op, arg2_type(x));// 将第二个参数转为 arg2_type 类型
}
// 将某个接受两个参数的 Adaptable Bunary function 转换为 Unary Function
template<class Operation>
class binder2nd : public unary_function<
    typename Operation::first_argument_type, 
    typename Operation::result_type> 
{
protected:
    Operation op;
    typename Operation::second_argument_type value;
public:
    // 构造函数
    binder2nd(const Operation& x, // 第一个参数就是两个参数的函数
              const typename Operation::second_argument_type& y) // 第二个参数
        : op(x), value(y){}
    typename Operation::result_type
    operator()(const Operation::first_argument_type& x) const {
        return op(x, value);
    }
};
conut_if
template <class InputIterator, class Predicate>
typename iterator_traits<InputIterator>::difference_type
count_if(InputIterator first, InputIterator last, 
         Predicate pred) {//保持条件判断类函数
    typename iterator_traits<InputIterator>::difference_type n = 0;
    for (; first != last; ++first) {
        if (pred(*first)) // 每次判断时执行类函数
            ++n;
    }
    return n;
}
not1
template<class Predicate>
class unary_negate : public unary_function<typename Predicate::argument_type, bool> {
protected:
    Predicate pred;
public:
    explicit unary_negate(const Predicate& x) : pred(x) {}
    bool operator()(typename Predicate::argument_type& x) const {
        return !pred(x);
    }
};
bind
可以绑定:
- functions
- function objects
- member functions,_1 必须是某个 object 地址
- data members,_1 必须是某个 object 地址
返回一个function object ret,调用 ret 相当于调用上述 1,2,3或相当于取出 4
// binding functions
std::divides<double> my_divide;
bind(my_divide, 10, 2); // return 10/2 , 5
bind(my_divide, placeholders::_1, 2); // return x/2
bind(my_divide, placeholders::_1, placeholders::_2); // return x/y
bind<int>(my_divide, placeholders::_2, placeholders::_1); // return int(y/x)
// binding members
struct MyPair {
    double a, b;
    double multiply() {return a * b;}
};
MyPair ten_two {10, 2};
// member function (即类的成员函数MyPair::multiply) 第一个参数是指向对象本身的指针参数 this
auto bound_memfn = bind(&MyPair::multiply, placeholders::_1); // return x.multiply()
bound_memfn(ten_two); // 20
auto bound_memdata = bind(&MyPair::a, ten_two); // return ten_two.a
bound_memdata(); // 10
auto bound_memdata2 = bind(&MyPair::b, placeholders::_1);//使用占位符表示暂时不绑定this指针 return x.b
bound_memdata2(ten_two); // 2
auto fn = bind(less<int>(), _1, 50); // bind2nd(less<int>(), 50)
count_if(vec.cbegin(), vec.end(), fn);
Iterator Adapters 迭代器适配器
reverse_iterator
reverse_iterator
rbegin() {
    return reverse_iterator(end());
}
reverse_iterator
rend() {
    return reverse_iterator(begin());
}

template <class Iterator>
class reverse_iterator {
protected:
    Iterator current; // 对应正向迭代器
public:
    // 逆向迭代器的5种 associated types 都和其对应的正向迭代器相同
    typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
    typedef typename iterator_traits<Iterator>::value_type value_type;
    typedef Iterator iterator_type;           正向迭代器
    typedef reverse_iterator<Iterator> self;  逆向迭代器
    
    explicit reverse_iterator(iterator_type x) : current(x) {}
    reverse_iterator(const self& x) : current(x.current) {}
    iterator_type base() const { return current; }
    // 对逆向迭代器取值,就是将对应正向迭代器退一位取值
    reference operator*() const { Iterator tmp = current; return *--tmp; }
    pointer operator->() const { return &(operator*()); }
    self& operator++() { --current; return *this; }
    self& operator--() { ++current; return *this; }
    self operator+(differnece_type n) const { return self(current - n); }
    self operator-(differnece_type n) const { return self(current + n); }
};
inserter
auto it = foo.begin();
advance(it, 3); // 迭代器向前走3步
copy(bar.begin(), bar.end(), inserter(foo, it));//这种写法本质上是不断插入
foo : 1 2 3 4 5
bar : 7 8 9
=>    1 2 3 7 8 9 4 5
    
template<class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result) {
    while (first != last) {
        *result = *first; // inserter重载了操作符,所以在赋值时不是单纯的拷贝,而是申请空间再拷贝
        ++reslut; first;
    }
}
// 辅助函数,帮用户获取 insert_iterator
template<class Container>
inline insert_iterator<Container>
inserter(Container& x, Iterator i) {
    typedef typename Container::iterator iter;
    return insertor<Container>(x, iter(i));
}
// 这个adapter将迭代器的赋值操作改为insert操作,并且移动迭代器。如此实现表面赋值,实际上insert
template<class Container>
class insert_iterator {
protected:
    Container* constainer;  // 底层容器
    typename Container::iterator iter;
public:
    typedef output_iterator_tag iterator_category; // 标出迭代器类型
    insert_iterator(Container& x, typename Container::iterator i)
        : container(&x), iter(i) {}
    insert_iterator<Container>&
    operator==(const typename Container::value_type& value) {
        iter = container->insert(iter, value); // 插入元素
        ++iter; // 令迭代器永远跟着target移动
        return *this;
    }
}
copy 函数只是按照指针位置逐个空间赋值,inserter 保证每个插入的元素都存储在新申请的空间
ostream_iterator
重写了 operator== 方法
vector<int> myvector{1,2,3,4,5};
ostream_iterator<int> out_it(cout, ",");
copy(myvector.begin(), myvector.end(), out_it);
// 输出 "1,2,3,4,5,"
template<class T, class charT=char, class traits=char_traits<charT>>
class ostream_iterator : public iterator<output_iterator_tag, void, void, void, void> {
    basic_ostream<charT, traits> *out_stream;
    const charT *delim;
public:
    typedef charT char_type;
    typedef traits traits_type;
    typedef basic_ostream<charT, traits> ostream_type;
    ostream_iterator(ostream_type& s) : out_stream(&s), delim(0) {}
    ostream_iterator(ostream_type& s, const charT *delimiter) 
        : out_stream(&s), delim(delimiter) {}
    ostream_iterator(const ostream_iterator<T, charT, traits>& x) 
        : out_stream(x.out_stream), delim(x.delim) {}
    ~ostream_iterator() {}
    // 操作符重载使得赋值变为输出
    ostream_iterator<T, charT, traits>& operator= (const T& value) {
        *out_stream << value;
        if (delim != 0) 
            *out_stream << delim;
        return *this;
    }
    
    ostream_iterator<T, charT, traits>& operator*() { return *this; }
    ostream_iterator<T, charT, traits>& operator++() { return *this; }
    ostream_iterator<T, charT, traits>& operator++(int) { return *this; }
};
istream_iterator
istream_iterator<double> eos; // 没有参数的空istream用于作标兵
// 初始化调用++操作,读取数据
istream_iterator<double> iit(cin);
if (iit != eos)
    value1 = *iit;
// 读取数据
++iit;
if (iit != eos)
    value2 = *iit;
istream_iterator<int> iit(cin), eos;
copy(iit, eos, inserter(c, c.begin()));
template<class T, class charT=char, class traits=char_traits<charT>, class Distance=ptrdiff_t>
class istream_iterator : public iterator<input_iterator_tag, T, Distance, const T*, const T&> {
    basic_istream<charT, traits> *in_stream;
    T value;
public:
    typedef charT char_type;
    typedef traits traits_type;
    typedef basic_istream<charT, traits> istream_type;
    
    istream_iterator() : in_stream(0) {}
    istream_iterator(istream_type& s) : in_stream(&s) { ++*this; }
    istream_iterator(const istream_type<T, charT, traits, Distance>& x) 
        : in_stream(x.in_stream), value(x.value) {}
    ~istream_iterator() {}
    
    const T& operator*() const { return value; }
    
    
    const T* operator->() const { return &value; }
    // ++ 操作会导致读取数据
    istream_iterator<T, charT, traits, Distance>& operator++() {
        if (in_stream && !(*in_stream >> vlaue))
            in_stream = 0;
        return *this;
    }
    istream_iterator<T, charT, traits, Distance> operator++(int) {
        istream_iterator<T, charT, traits, Distance> tmp = *this;
        ++*this;
        return tmp;
    }
};
标准库之内 STL之外
万用 Hash Function
class CustomerHash {
public:
    // 自定义求hash的类函数
    size_t operator()(const Customer& c) const {
        return hash_val(c.xxx, c.yyy, c.zzz);//没有传入 seed,调用下方第一个函数
    }
};
/************    万能的哈希函数        ***********/
template<typename... Type>
inline size_t hash_val(const Types&... args) {
    size_t seed = 0;
    hash_val(seed, args...);
    return seed; // 返回值为 seed
}
template<typename T, typename... Type>//逐一取出 value,将n个变为 1 + (n-1) 个 variadic templates
inline size_t hash_val(size_t& seed, const Types&... args) {
    hash_combine(seed, val);
    hash_val(seed, args...);
}
template<typename T>//处理只有一个 value 的情况
inline void hash_val(size_t& seed, const T& val) {
    hash_combine(seed, val);
}
template<typename T>
inline void hash_combine(size_t& seed, const T& val) {
    seed ^= std::hash<T>()(val) + 0x9e377b9 + (seed<<6) + (seed>>2);
}
标准库提供
#include <hash_fun.h>
hash 类函数
Tuple
一组类型数据的组成的元组,重写了 < = 等操作符
使用:
tuple<string, int, int, complex<double>> t;
sizeof(t); // 32
tuple<int, float, string> t1(41, 6.3, "nico");
cout << "t1: " << get<0>(t1) << get<1>(t1) << get<2>(t2) << endl;
auto t2 = make_tuple(22, 44, "str");
get<1>(t1) = get<1>(t2);
int i; float f; string s;
tie(i, f, s) = t1; // 一次性将tuple的元素拿出,赋值到各个变量
 
实现
template<typename... Values> class tuple;
template<> class tuple<> {};
template<typename Head, typename... Tail> 
class tuple<Head, Tail> : private tuple<Tail...> {
    typedef tuple<Tail...> inherited;
public:
    tuple() {}
    tuple(Head v, Tail... vtail) : m_head(v), inherited(vtail...) {}
    
    typename Head::type head() { return m_head; }
    inherited& tail() { return *this; } // 通过强转去除头元素
protected:
    Head m_head; // 在初始化时赋值头元素
};
tuple<int, float, string> -继承-> tuple<float, string> -继承-> tuple<string> -继承-> tuple<>
type traits
类型萃取 在编译期计算、查询、判断、转换和选择,增强了泛型编程的能力,使得我们在编译期就能做到优化改进甚至排错
template<typename type>//泛化
struct __type_traits {
    typedef __true_type this_dummy_member_must_be_first;
    typedef __false_type has_trival_default_constructor;
    typedef __false_type has_trival_copy_constructor;
    typedef __false_type has_trival_assignment_operator;
    typedef __false_type has_trival_destructor;
    typedef __false_type is_POD_type; // POD Plain Old Data,c语言种struct,只有数据没有函数
};
template<>//特化
struct __type_traits<int> {
    typedef __true_type has_trival_default_constructor;//表示默认构造函数不重要
    typedef __true_type has_trival_copy_constructor;
    typedef __true_type has_trival_assignment_operator;
    typedef __true_type is_POD_type; // POD Plain Old Data
};
// 对于自定义类需要自定义特化模板
// 通过获取 __type_traits<Foo>::has_trival_destructor 的值得知类的析构函数是否重要,并决定出最佳的操作
is_void 源码
template<typaname>
struct __is_void_helper : public false_type {};
template<>
struct __is_void_helper<void> : public true_type {};
template<typename _Tp>
struct is_void : public __is_void_helper<typename remove_cv<_Tp>::type>::type {};
// remove_cv
template<typename _Tp>
struct remove_cv {
    typedef typename remove_const<typename remove_volatile<_Tp>::type>::type type;
};
// remove_const
template<typename _Tp>
struct remove_const { typedef _Tp type; };
template<typename _Tp>
struct remove_const<_Tp const> { typedef _Tp type; };
// remove_volatile
template<typename _Tp>
struct remove_volatile { typedef _Tp type; };
template<typename _Tp>
struct remove_volatile { typedef _Tp type; };
// add_const
template<typename _Tp>
struct add_const { typedef _Tp const type; };
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号