1、在迭代器的设计上,除了提供统一的元素访问界面之外,还需要兼顾数组这种最原始容器,但是数组类型没有嵌套类型定义:value_type等
解决方法:要统一数组和容器,需要借助一个类模板和模板特例功能来统一描述迭代器与指针的特性。该模板只用来嵌套定义元素值类型,如果模板参数是一个迭代器,则提取元素值类型并重新定义;如果模板参数是一个指针,则该类模板中为指针定义其元素值类型。显然,需要模板通例用于描述迭代器,而特例用于描述指针。
//迭代器特性模板,通例
template<typename I>
struct iterator_traits
{
typedef typedename I::value_type value_type;
};
//迭代器特性模板,特例,用于指针
template<typename p>
struct iterator_traits<p*>
{
typedef p value_type;
};
应用:
template<typename I>
typename iterator_traits<I>::value_type
sum(I begin, I end)
{
typedef typename iterator_traits<I>::value_type value_type;
value_type sum(0);
for(;begin != end; ++begin)
sum += *begin;
return sum;
}
2、标准库中可接受分配器的容器模板包括:
序列容器:vector、deque、list、forward_list
集合容器:set、multiset、map、multimap
散列容器:unordered_set、unordered_multiset、unordered_map、unordered_multimap
详细模板参数列表:
template<class Value, class Alloc = allocator<Value>>
class vector; //list, forward_list,deque同
template<class Value, class Compare = less<Value>, class Alloc = allocator<Value>>
class set;
template<class Key, class Value, class Compare = less<Key>, class Alloc = allocator<pair<const Key, Value>>>
class map;
template<class Value, class Hash = hash<Value>, class Pred = equal_to<Value>, class Alloc = allocator<Value>>
class unordered_set;
template<class Key, class Value, class Hash = hash<Key>, class Pred = equal_to<Key>, class Alloc = allocator<pair<const Key, Value>>>
class unorderd_map;
当需要定制容器的内存操作时,可以按照标准中的分配器规范,将内存操作封装在一个新的分配器类模板中并传入容器模板,如:
std::list<my_data, my_allocator<my_data>>custom_list;
3、有态分配器--拥有非静态成员变量的分配器;无态分配器---像std::allocator<T>那样只是调用new/delete操作符在"全局"内存范围内工作的分配器并不需要成员变量
4、list及搜索树容器需要反复插入与删除数据,若采用默认的分配器std::allocator则会频繁地向系统申请及释放内存,应对频繁的申请与释放最常用的技术是缓冲。
1)若已知每次申请释放的内存空间尺寸固定不变,那么缓冲区内部的管理算法可以大大简化,最简单的情况下,可将所申请的整块内存划分为同等尺寸的若干内存块并以链表形式串联在一起,每当响应内存申请时则从链表中取出内存块插入链表即可。这种缓冲固定尺寸内存块的管理方式称为对象池。
4、宏 size_t offsetof(structName, memberName)
该宏用于求结构体中一个成员在该结构体中的偏移量。
5、前向迭代器和输入迭代器二者都提供自加1操作前移一位以及引用取值,关键区别在于前向迭代器能够保证两个迭代器实例a与b如果满足a==b,则也一定满足++a==++b,但输入迭代器不能保证这一点。
6、迭代器转换器
1)反转迭代器 ------ reverse_iterator<T>
注:对反转迭代器的去引用操作将返回其所指位置后退1位的数据引用。
char array[] = "madam I'm Adam";
typedef reverse_iterator<
char*>backward_iterator;
2)插入迭代器 ------ back_insert_iterator<C>(在容器末端插入数据)、front_insert_iterator<C>(在容器前端插入数据)、insert_iterator<C>(在容器的指定位置插入数据)
以及三个助手函数模板:back_inserter(c)、front_inserter(c)、inserter(c,i)。
3)流迭代器 ------- istream_iterator(输入流迭代器)、ostream_iterator(输出流迭代器)、istreambuf_iterator(输入流缓冲区迭代器)、ostreambuf_iterator(输出流缓冲区迭代器)
注:istream_iterator通过">>"操作符从流中读取数据,这是一种相对“高级”的流取数据操作,故有时它无法用于检测“空格”的 出现次数。
注:当为标准库中的容器或其他类重载">>"、"<<"操作符以用于流迭代器及标准算法时,需要将该重载操作符写在std命名空间内。
7、将成员函数指针赋给一个必须有明确函数形式的成员函数指针变量,注:有时成员函数有重载,故必须明确函数形式。
如:size_type (container_type::*erase_func) (key_type const&) = &container_type::erase;
8、自定义迭代器
1)template<typename T> class skip_iterator : public std::iterator<std::random_access_iterator_tag, T>
{
//自定义元素类型 ....
//嵌套类型定义
typedef std::iterator<std::random_access_iterator_tag, T> base_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::reference reference;
//构造函数....
//重载符号函数等等。。。。
};
2)template<typename T, typename BinFunc>class accumulate_iterator : public std::iterator<std::output_iterator_tag, T>
{
//自定义元素类型
//构造函数
//重载符号函数。。。
//重载赋值运算符函数
template<typename T0>
T0 const& operator = (T0 const &v) { ref_x = bin_fun(ref_x, v); }
};
//生成accumulate_iterator助手函数
template<typename T, typename BinFunc>accumulate_iterator<T, BinFunc> accumulater(T &ref_x, BinFunc bin_func)
{
return accumulate_iterator<T, BinFunc>(ref_x, bin_func);
}
9、C++11新增语法:右值引用
1)某一类型T的右值引用类型写为
T&&,相应的原有引用类型T&现在称为左值引用。
2)右值引用赋予了我们更改右值内容的权利。如左值引用类型一样,右值引用类型可用于函数参数,也可以用于声明局部变量(............................).
3)以
右值引用为参数的构造函数和赋值操作符函数被称为
移动构造函数及移动赋值操作符。
4)编译器创建及管理的无名空间是一种狭义右值,在C++11标准中称为纯右值。而实际上能够促使编译器匹配右值引用参数的,不仅仅是狭义右值,还有可能是强制转义成右值引用的左值。std::move 是C++11标准库中新增的一个函数模板,其作用就是将一左值强制转义为右值引用。