STL源码剖析 入门开始 STL概论与版本简介

  • 源代码之中时而会出现一些全局函数调用操作,尤其是定义于<stl_construct.h> 之中用于对象构造与析构的基本函数,以及定义于<stl_uninitialized.h>之 中 用 于 内 存 管 理 的 基 本 函 数 , 以及定义于<stl_algobase.h>之中的各种基本算法

STL六大组件功能与运用

  • 容 器 (containers) : 各种数据结构,如  vector, list , deque, set, map,用来存放数据,详见本书4, 5 两章。从实现的角度来看,STL容器是一种class template.就体积而言,这一部分很像冰山在海面下的比率
  • 算 法 (algorithm s): 各种常用算法如 sort, search, copy, erase - - 详见 第 6 章。从实现的角度来看,STL算法是一种function template.
  • 迭代器(iterators): 扮演容器与算法之间的胶合剂,是所谓的“泛型指针”, 详见第3 章.共有五种类型,以及其它衍生变化.从实现的角度来看,迭代器是一种将 operator*, operator->, operator++, operator--等指针相关操作予以重载的class template.所有STL容器都附带有自己专属的迭代器—— 是的,只有容器设计者才知道如何遍历自己的元素。原生指针(native
    pointer)也是一种迭代器。
  • 仿函数(functors): 行为类似函数,可作为算法的某种策略(p olicy), 详见 第7章。从实现的角度来看,仿函数是一种重载了 operator ()的class或 class template. 一般函数指针可视为狭义的仿函数。
  • 配 接 器 (adapters): —种用来修饰容器(containers)或仿函数(functors)或迭代器(iterators)接口的东西,详见第8 章• 例如,STL提供的queue和 stack,虽然看似容器,其实只能算是一种容器配接器,因为它们的底部完全 借助deque,所有操作都由底层的deque供应。改变functor接口者,称为function adapter;改变 container 接口者,称为 container adapter;改变 iterator
    接口者,称 为 iterator adapter.配接器的实现技术很难一言以蔽之,必须逐 —分析,详见第8章
  • 配置器(allocators): 负责空间配置与管理,详见第2 章。从实现的角度来 看,配置器是一个实现了动态空间配置、空间管理、空间释放的class template.

1.8.3 SGI STL 的 编 译 器 组 态 设 置 ( configuration )

  • 不同的编译器对C++语言的支持程度不尽相同。作为一个希望具备广泛移植能力的程序库,SGI S T L 准备了一个环境组态文件<stl_config.h>,其中定义了许多常量,标示某些组态的成立与否。所有STL头文件都会直接或间接包含这个组态文件,并以条件式写法,让预处理器(pre-processor)根据各个常量决定取舍哪 一段程序代码。例如:

  •  <stl_Config.h>文件起始处有一份常量定义说明,然后即针对各家不同的编 译器以及可能的不同版本,给予常量设定。从这里我们可以一窥各家编译器对标准C++的支持程度。
  • 所谓临时对象,就是一种无名对象(unnamed objects) >,它的出现如果不在程 序员的预期之下(例如任何pass by value操作都会引发copy操作,于是形成一 个临时对象),往往造成效率上的负担。但有时候刻意制造一些临时对象,却又是使程序干净清爽的技巧。
  • 刻意制造临时对象的方法是,在型别名称之后直接加一对小括号,并可指定初值,例 如 Shape (3,5)或 int(8),其意义相当于调用相应 的constructor且不指定对象名称
  • STL 最常将此技巧应用于仿函数(functor)与 算法的搭配上,例如:
  • 最后一行便是产生function template具现体print<int>的一个临时对象。 这个对象将被传入for_each()之中起作用。当 for_each()结束时,这个临时对 象也就结束了它的生命。
#include <iostream>
#include <algorithm>
#include <iterator>
#include <set>
#include <vector>
#include <functional>
#include <deque>template <typename T>
class print{
public:void operator() (const T& elem) {//operator() 重载std::cout << elem << std::endl;}
};
int main(int argc,char* argv[]){int ia[6] = {0,1,2,3,4,5};std::vector<int>iv(ia,ia+6);std::for_each(iv.begin(),iv.end(), print<int>());
}
  • 静态常量整数成员在c la ss内部直接初始化 in-class static constant integer initialization
  • 如 果 class内含 const static integral data m e m b e r , 那么根据 C + + 标准规格,
    我们可以在class之内直接给予初值。所 谓 integral泛指所有整数型别,不单只是 指 int。下面是一个例子:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <set>
#include <vector>
#include <functional>
#include <deque>template <typename T>
class print{
public:void operator() (const T& elem) {//operator() 重载std::cout << elem << std::endl;}
};template <typename T>
class testClass{
public:static const int _datai = 5;static const long _datal = 3L;static const char _datac = 'c';
};
int main(int argc,char* argv[]){std::cout << testClass<int>::_datai << std::endl;std::cout << testClass<int>::_datal << std::endl;std::cout << testClass<int>::_datac << std::endl;
}
  • increm ent/decrem ent/dereference 操作符
  • increment/dereference操作符在迭代器的实现上占有非常重要的地位,因为 任何~个迭代器都必须实现出前进(讥er e * ” 和取值(dereference, operator*) 功能,前者还分为前置式(prefix)和后置式(postfix)两种,有非常 规律的写法14°有些迭代器具备双向移动功能,那么就必须再提供decrement操作 符 (也分前置式和后置式两种)。下面是一个范例:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <set>
#include <vector>
#include <functional>
#include <deque>template <typename T>
class print{
public:void operator() (const T& elem) {//operator() 重载std::cout << elem << std::endl;}
};template <typename T>
class testClass{
public:static const int _datai = 5;static const long _datal = 3L;static const char _datac = 'c';
};class INT{friend std::ostream& operator<<(std::ostream & os,const INT& i);
public:INT(int i) : m_i(i){};//prefix : increment and then fetchINT& operator++(){++(this->m_i); //随着class的不同,此行应该有不同的操作return *this;}//postfix : fetch and then incrementconst INT operator++(int){INT temp = *this;++(*this);return temp;}//postfix : decrement and then fetchINT& operator--(){--(this->m_i);return *this;}//postfix : fetch and then decrementconst INT operator--(int){INT temp = *this;--(*this);return temp;}//dereferenceint& operator*() const{return (int&)m_i;//以上转换操作告诉编译器,你确实要将const int转为non-const lvalue.//如果没有这样明白地转型,有些编译器会给你警告,有些更严格的编译器会视为错误}private:int m_i;
};std::ostream& operator<<(std::ostream&os,const INT& i){os << '[' << i.m_i << ']';return os;
}int main(int argc,char* argv[]){INT I(5);std::cout << I++;std::cout << ++I;std::cout << I--;std::cout << --I;std::cout << *I;
}
  • 前 闭 后 开 区 间 表 示 法 [)
  • 任何一个STL算法,都需要获得由一对迭代器(泛型指针)所标示的区间,用以表示操作范围。这一对迭代器所标示的是个所谓的前闭后开区间15,以 [first, last)表示。也就是说,整个实际范围从first开始,直到last-1.迭代器last 所指的是“最后一个元素的下一位置”。这种off by one (偏移一格,或说pass the end)的标示法,带来了许多方便,例如下面两个STL算法的循环设计,就显得干净利落:
  • 因为 以下两个函数都是递增遍历元素,所以使用 InputIterator
template <class InputIterator,class T>
InputIterator find(InputIterator first,InputIterator last,const T& value){while(first != last && *first!= value){return first;}
}template <class InputIterator,class Function>
Function for_each(InputIterator first,InputIterator last,Function f){for (; first != last;++first) {f(*first);}return f;
}

  •  function call 操 作 符 ( o p e r a to r 。)
  • 很少有人注意到,函数调用操作(C ++语法中的左右小括号)也可以被重载
  • 许多STL算法都提供了两个版本,一个用于一般状况(例如排序时以递增方式排列),一个用于特殊状况(例如排序时由使用者指定以何种特殊关系进行排列)。像这种情况,需要用户指定某个条件或某个策略,而条件或策略的背后由一整组操作构成,便需要某种特殊的东西来代表这“一整组操作”
  • 代表“一整组操作”的,当然是函数• 过去C 语言时代,欲将函数当做参数传递 ,唯有通过函数指针(pointer to function,或 称 function pointer)才能达成,例如:

  •  但是函数指针有缺点,最重要的是它无法持有自己的状态(所谓局部状态,local states), 也无法达到组件技术中的可适配性(adaptability)—— 也就是无法再将某 些修饰条件加诸于其上而改变其状态。
  • 为此,S T L 算法的特殊版本所接受的所谓“条件”或 “策略”或 “一整组操作”,都以仿函数形式呈现。所谓仿函数(functor)就是使用起来像函数一样的东 西。如果你针对某个class进 行 operator()重载,它就成为一个仿函数。至于要 成为一个可配接的仿函数,还需要做一些额外的努力(详见第8 章 )。
  • 上 述 的 plus<T>和 minus<T>已经非常接近STL的实现了,唯一的差别在 于 它 缺 乏 “可配接能力”。关 于 “可配接能力
template <class T>
struct plus{T operator() (const T&x,const T&y) const{return x+y;}
};template <class T>
struct minus{T operator()(const T&x,const T&y) const{return x-y;}
};int main(int argc,char* argv[]){plus<int>plus_obj{};minus<int>minus_obj{};//以下使用仿函数,就像使用一般函数一样std::cout << plus_obj(3,5) << std::endl;std::cout << minus_obj(3,5) << std::endl;//以下直接产生仿函数的临时对象(第一对小括号),并调用之(第二对小括号)std::cout << plus<int>()(3,5) << std::endl;std::cout << minus<int>()(5,3) << std::endl;
}

请使用手机"扫一扫"x

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446420.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中科大 计算机网络4 网络核心Core 分组交换 电路交换

网络核心 电路交换&#xff08;线路交换&#xff09;&#xff1a;打电话之前&#xff0c;先建立一条链路&#xff08;物理&#xff09; 分组交换&#xff1a;存储转发的方式 电路交换&#xff08;线路交换&#xff09; 通过信令&#xff08;控制信息&#xff0c;如&#xf…

STL 源码剖析 空间配置器

以STL的运用角度而言&#xff0c;空间配置器是最不需要介绍的东西&#xff0c;它总是隐藏在一切组件&#xff08;更具体地说是指容器&#xff0c;container&#xff09; 的背后但是STL的操作对象都存放在容器的内部&#xff0c;容器离不开内存空间的分配为什么不说allocator是内…

中科大 计算机网络7 分组延迟 分组丢失 吞吐量

分组丢失和延迟的原因 队列太长没有意义&#xff0c;用户需求 排队&#xff1a;输出能力<到来的分组&#xff0c;需要等待 四种分组延迟 节点处理延迟&#xff1a;确定的 排队延迟&#xff1a;随机&#xff0c;取决于网络情况 一个比特的传输时间&#xff1a; R1Mbps …

STL源码剖析 迭代器iterator的概念 和 traits编程技法

iterator模式定义如下&#xff1a;提供一种方法&#xff0c;使之能够依序巡访某个 聚合物(容器)所含的各个元素&#xff0c;而又无需暴露该聚合物的内部表述方式.STL的中心思想在于&#xff1a;将数据容器(containers)和算法(algorithms)分开&#xff0c;彼此独立设计&#xff…

中科大 计算机网络11 应用层原理

应用层大纲 传输层向应用层提供的服务&#xff0c;形式是Socket API&#xff08;原语&#xff09; 一些网络应用的例子 互联网层次中&#xff0c;应用层协议最多 流媒体应用&#xff1a;直播 网络核心最高的层次就是网络层 应用进程通信方式 C/S&#xff1a; 客户端&…

STL源码剖析 序列式容器 vector 和 ilist

Vector list 单向链表 ilistlist的删除操作&#xff0c;也只有指向被删除元素的迭代器会失效&#xff0c;其他迭代器不会受到影响

中科大 计算机网络5 接入网和物理媒体

接入网 接入网&#xff1a;把边缘&#xff08;主机&#xff09;接入核心&#xff08;路由器&#xff0c;交换机&#xff09; 骨干网【连接主机和主机】和接入网中都有物理媒体 接入方式&#xff1a;有线和无线 带宽共享/独享 接入网&#xff1a;住宅接入modem modem调制解调…

STL源码剖析 序列式容器 deque双端队列

相较于vector的内存拷贝&#xff0c;deque在内存不足时只需要进行内存的拼接操作即可&#xff0c;不需要重新配置、复制、释放等操作&#xff0c;代价就是迭代器的架构不是一个普通的指针&#xff0c;比较复杂d e q u e 的迭代器 deque是分段连续空间。维持其“整体连续”假象…

中科大 计算机网络6 Internet结构和ISP

互联网的结构 端系统通过接入ISPs接入互联网 n个ISP互相连接&#xff1a; IXP,Internet exchage point:互联网接入点&#xff0c;互联网交互点 ISP&#xff1a;互联网服务提供商&#xff0c;提供接入&#xff0c;提供网络【中国移动&#xff0c;中国电信】 ICP&#xff1a…

STL源码剖析 Stack栈 queue队列

随机迭代器用于随机数据访问&#xff0c;所以栈stack不具备此功能

中科大 计算机网络8 协议层次和服务模型

协议层次 协议层次&#xff1a;现实生活中的例子 分层 分层处理和实现复杂系统 图中&#xff0c;左边是模块&#xff0c;右边是分层 计算机的设计是分层&#xff0c;每一层实现一个或一组功能&#xff0c;下层向上层提供服务&#xff1b;但效率比较低 对等层实体通过协议来交换…

STL源码剖析 heap堆结构

heap一般特指max-heap&#xff0c;即最大的元素位于heap和array的首部 heap不提供遍历功能&#xff0c;也不提供迭代功能

中科大 计算机网络9 互联网历史

总纲 计算机网络 早期1960以前 1961-1972 NCP协议&#xff1a;相当于现在的TCP和IP协议 每个节点即是数据的源也是数据的目标

STL源码剖析 序列式容器 slist

STL l i s t 是个双向链表(double linked lis t) 。SGI STL提供了一个单向链 表 (single linked lis t) , 名 为 slist s l i s t 和 l i s t 的主要差别在于&#xff0c;前者的迭代器属于单向的Forwardlterotor, 后者的迭代器属于双向的Bidirectional Iterator.为此&#xff0…

中科大 计算机网络12 Web和HTTP

Web与HTTP 对象&#xff1a;web页中其实是对象链接 URL&#xff1a;通用资源定位符【任何对象都可以使用URL来唯一标识】 用户名&#xff1a;口令【支持匿名访问&#xff0c;用户名和口令不计】 端口&#xff1a;HTTP&#xff1a;80 FTP&#xff1a;21【使用默认端口号&#x…

STL源码剖析 关联式容器 树 红黑树、二叉搜索树、平衡二叉搜索树

所谓关联式容器&#xff0c;观念上类似关联式数据库(实际上则简单许多)&#xff1a;每笔数据(每个元素)都有一个键值(key)和一个实值(value) 2。当元素被插入到关联式 容器中时&#xff0c;容器内部结构(可能是RB-tree,也可能是hash-table)便依照其键 值大小&#xff0c;以某种…

北京大学 软件工程1 软件 软件工程 软件开发 软件工程框架

软件的定义 重新定义软件 新一代信息技术 区块链 创造性思维 软件的特点 软件的种类 支撑软件&#xff1a;VC&#xff0c;PyCharm等 应用软件&#xff1a;QQ&#xff0c;微信 软件工程的起源 软件开发的三个阶段 软件工程概念的提出 软件工程的定义 软件工程将系统化&#…

java学习_Python基础学习教程:从0学爬虫?让爬虫满足你的好奇心

Python基础学习教程&#xff1a;从0学爬虫&#xff1f;让爬虫满足你的好奇心有必要学爬虫吗&#xff1f;我想&#xff0c;这已经是一个不需要讨论的问题了。爬虫&#xff0c;“有用”也“有趣”&#xff01;这个数据为王的时代&#xff0c;我们要从这个庞大的互联网中来获取到我…