1、容器的定义
容器:专门用于某种形式组织及存储数据的类称为“容器”。
 
2、容器与迭代器
迭代器:封装了对容器虚拟数据序列的操作并按约定提供统一界面以遍历容器内容的代理类即为迭代器。
 
举例理解:
template<typename T> class list;

template<typename T>
struct list_node
{
typedef T value_type;
typedef T& reference_type;
typedef const T const_reference_type; T value;
list_node *prev;
list_node *next; list_node(T const &value, list_node *prev, list_node *next) :
value(value), prev(prev), next(next){}
}; template<typename N>
class list_iterator
{
N *pos;
template<typename T> friend class list; public:
typedef typename N::value_type value_type;
typedef typename N::reference_type reference_type;
typedef typename N::const_reference_type const_reference_type;
typedef list_iterator<N> self_type; list_iterator() :pos(){}
list_iterator(N *pos) :pos(pos){} bool operator != (self_type const &right) const{
return pos != right.pos;
} bool operator == (self_type const &right) const{
return pos != right.pos;
} self_type& operator++(){
if (pos) pos = pos->next;
return *this;
} reference_type operator * () throw (std::runtime_error){
if (pos) return pos->value;
else throw (std::runtime_error("null iterator!\n"));
}
}; template<typename T>
class list
{
typedef list_node<T> node_type;
node_type *head; public:
typedef T value_type;
typedef list_iterator<node_type> iterator; list() :head(){}
~list(){
while (head)
{
node_type *n = head;
head = head->next;
delete n;
}
} void push_front(T const &v)
{
head = new node_type(v, , head);
if (head->next)
{
head->next->prev = head;
}
} void pop_front(T const &v)
{
if (head)
{
node_type *n = head;
head = head->next;
head->prev = ;
delete n;
}
} void insert(iterator it, T const &v)
{
node_type *n = it.pos;
if (n)
{
node_type *new_node = new node_type(v, n, n->next);
new_node->next->prev = new_node;
n->next = new_node;
}
} void erase(iterator &it)
{
node_type *n = it.pos;
++it;
if (n)
{
if (n->next)
{
n->next->prev = n->prev;
}
if (n->prev)
{
n->prev->next = n->next;
}
if (head == n)
{
head = n->next;
}
delete n;
}
} bool is_empty() const { return head == ; }
iterator begin(){ return iterator(head); }
iterator end(){ return iterator(); }
};
针对树形结构节点类型的迭代器:
template<typename T>
struct tree_node
{
typedef T value_type;
typedef T& reference_type;
typedef const T& const_reference_type; T value;
tree_node *parent;
tree_node *left;
tree_node *right; tree_node(T const &value,
tree_node *parent,
tree_node *left,
tree_node *right):
value(value),
parent(parent),
left(left),
right(right){} ~tree_node()
{
if (left) delete left;
if (right) delete right;
}
}; template<typename N>
class tree_iterator
{
const N *pos;
public:
typedef typename N::value_type value_type;
typedef typename N::const_reference_type const_reference_type;
typedef tree_iterator<N> self_type; tree_iterator() :pos(){}
tree_iterator(const N *pos) :pos(pos){} bool operator == (self_type const &right) const{
return pos == right.pos;
} self_type& operator ++ (){
if (pos){
if (pos->right){
pos = pos->right;
while (pos->left)
{
pos = pos->left;
}
}
else
{
while (pos->parent && (pos->parent->right == pos))
{
pos = pos->parent;
}
pos = pos->parent;
}
}
return *this;
} const_reference_type operator * () const throw(std::runtime_error)
{
if (pos)
{
return pos->value;
}
else
{
throw std::runtime_error("Null iterator!\n");
}
}
}; template<typename T>
class set
{
typedef tree_node<T> node_type;
node_type *root;
public:
typedef T value_type;
typedef tree_iterator<node_type> const_iterator; set() :root(){}
~set(){ if (root) delete root; } bool insert(T const &v)
{
node_type **n = &root;
node_type *p = ;
while (*n)
{
if (v == (*n)->value)
{
return false;
}
else
{
p = *n;
n = v < (*n)->value ? &((*n)->left) : &((*n)->right);
}
}
*n = new node_type(v, p, , );
return true;
} bool has(T const &v)
{
node_type *n = root;
while (n)
{
if (v == n->value)
return true;
n = v < n->value ? n->left : n->right;
}
return false;
} bool is_empty() const { return root == ; } const_iterator begin() const{
node_type *n = root;
while (n->left) n = n->left;
return const_iterator(n);
} const_iterator end() const { return const_iterator(); }
};
尽管容器内部的数据结构类型不同(set是一个树形结构,而list是链表结构),但是提供给用户的操作界面iterator的所有操作都是相同的,所以底层数据结构对用户来说是透明的。
这也算是一种设计思路。
 
3、迭代器和算法
利用迭代器求和:
template<typename C>
typename C::value_type
sum(C &c)
{
typedef typename C::value_type value_type;
typedef typename C::iterator iterator;
value_type sum(); for (iterator i = c.begin(); i != c.end(); ++i)
{
sum += *i;
}
return sum;
}
不足1:只能求所有元素之和,不能求部分元素之和。可以将一个迭代器改为两个迭代器来弥补这里的不足。
template<typename I>
typename I::value_type
sum(I begin, I end)
{
typedef typename I::value_type value_type; value_type sum();
for (; begin != end; ++begin)
{
sum += *begin;
}
return sum;
}
不足2:要兼容最原始的容器——数组。
这里的I都是某种类型的迭代器,你可以通过I::value_type获取迭代器所指的对象的类型。但是数组的指针是一个普通的指针,是没有value_type成员的。借助另外一个类模板及模板特例功能来统一描述迭代器指针的特性。
 
再进行一层封装,使得普通的指针也有了value_type:
template<typename I>
struct iterator_traits
{
typedef typename 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();
for (; begin != end; ++begin)
{
sum += *begin;
}
return sum;
}
4、迭代器的陷阱
a、容器中通常有迭代器为参数对指定位置进行操作的成员函数,调用此类函数有个隐含要求,即迭代器所指数据来自该容器,否则后果无法预测。
b、由于迭代器独立于容器之外,用户可以一次性生成多个迭代器对容器内数据进行操作。这样就会产生冲突。

《深入实践C++模板编程》之五——容器与迭代器的更多相关文章

  1. 《深入实践C++模板编程》之六——标准库中的容器

    1.容器的基本要求 a.并非所有的数据都可以放进容器当中.各种容器模板对所存数据类型都有一个基本要求——可复制构造.将数据放进容器的过程就是通过数据的复制构造函数在容器内创建数据的一个副本的过程. b ...

  2. 《深入实践C++模板编程》之四——特例

    1. 所谓模板特例,是针对符合某种条件的模板参数值集合另外声明的模板实现变体. template<typename T> class my_vector; template<> ...

  3. 《深入实践C++模板编程》之三——模板参数类型详解

    非类型模板参数 和 模板型模板参数 整数以及枚举类型:指向对象或者函数的指针:对对象或函数的引用:指向对象成员的指针.统称为非类型模板参数. 模板型模板参数,是指模板参数还可以是一个模板.   1.整 ...

  4. 《深入实践C++模板编程》之二——模板类

    1.类的模板的使用 类,由于没有参数,所以没有模板实参推导机制. #include <stdexcept> template<typename T> class my_stac ...

  5. 《深入实践C++模板编程》之一——Hello模板

    1.通过一个简单的例子来理解模板的用途: 模板为不同类型的数据生成操作相同或相似的函数. 弱语言如Python,可以使用一种函数来应对各种类型,但是C++就不得不为不同的类型编写相似的函数.模板的作用 ...

  6. c++ 模板参数做容器参数迭代器报错 vector<T>::const_iterator,typename const报错

    错误1: template<class T>void temp(std::vector<T>& container){        std::vector<T& ...

  7. STL(标准模板库)理论基础,容器,迭代器,算法

    基本概念 STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.现然主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间.   ...

  8. C++之模板编程

    当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对象都具有共性. 比如 数值可以增加.减少:字符串也可以增加减少. 它们的动作是相似的, 只是对象的类型不同 ...

  9. c++ 基于Policy 的 模板编程

    在没真正接触c++  模板编程之前.真的没有想到c++ 还能够这么用.最大的感触是:太灵活了,太强大了. 最初接触模板威力还是在Delta3d中,感觉里面的模板使用实在是灵活与方便,特别是dtAI中使 ...

随机推荐

  1. Beta冲刺(2/5)

    队名:new game 组长博客 作业博客 组员情况 鲍子涵(队长) 过去两天完成了哪些任务 验收游戏素材 学习Unity 2D Animation系统 基本做完了人物的各个动画 接下来的计划 冲击E ...

  2. mysql5.7 彻底解决sql_mode=only_full_group_by

    ONLY_FULL_GROUP_BY是mysql默认的一种sql模式,其作用是约束sql语句:要求select中的所有字段,除复合函数外,全部要出现在group by中. 默认这种模式是有原因的,因为 ...

  3. POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE

    POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...

  4. 3.JSON使用

    把 JSON 文本转换为 JavaScript 对象 JSON 最常见的用法之一,是从 web 服务器上读取 JSON 数据(作为文件或作为 HttpRequest),将 JSON 数据转换为 Jav ...

  5. cat中文正常vi中文乱码

    Linux cat中文正常vi中文乱码 问题示例 出现此问题,有可能是vim 编辑器的配置编码方面的问题. 出现此情况,在vim 编辑器中输入 :e ++enc=utf8 :e ++enc=zh_CN ...

  6. Des加密类

    需要导入Base64.jar包 import java.io.IOException; import java.security.SecureRandom; import javax.crypto.C ...

  7. handler方法

    post(Runnable) postAtTime(Runnable,long) postDelayed(Runnable long) post类方法允许你排列一个Runnable对象到主线程队列中 ...

  8. Centos7.2 搭建emqttd集群,添加自启动服务

    关闭防火墙(可选):systemctl stop firewalld.service 1.安装依赖库> sudo yum -y install make gcc gcc-c++ kernel-d ...

  9. GitLab - 代码仓库管理工具GitLab简介

    1 - GitLab 基于git的开源的仓库管理系统项目,使用git作为代码管理工具,并在此基础上搭建web服务,拥有与Github类似的功能. 社区版(Community Edition,CE) 企 ...

  10. kubernetes/dashboard Getting Started

    Kubernetes Dashboard is a general purpose, web-based UI for Kubernetes clusters. It allows users to ...