网站制作 信科网络,个人创建网站,摄影网站设计方案,陕西省关于网站信息内容建设源代码之中时而会出现一些全局函数调用操作#xff0c;尤其是定义于stl_construct.h 之中用于对象构造与析构的基本函数#xff0c;以及定义于stl_uninitialized.h之 中 用 于 内 存 管 理 的 基 本 函 数 #xff0c; 以及定义于stl_algobase.h之中…源代码之中时而会出现一些全局函数调用操作尤其是定义于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具现体printint的一个临时对象。 这个对象将被传入for_each()之中起作用。当 for_each()结束时这个临时对 象也就结束了它的生命。
#include iostream
#include algorithm
#include iterator
#include set
#include vector
#include functional
#include dequetemplate 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::vectorintiv(ia,ia6);std::for_each(iv.begin(),iv.end(), printint());
}
静态常量整数成员在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 dequetemplate 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 testClassint::_datai std::endl;std::cout testClassint::_datal std::endl;std::cout testClassint::_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 dequetemplate 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::ostreamos,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 章 )。上 述 的 plusT和 minusT已经非常接近STL的实现了唯一的差别在 于 它 缺 乏 “可配接能力”。关 于 “可配接能力
template class T
struct plus{T operator() (const Tx,const Ty) const{return xy;}
};template class T
struct minus{T operator()(const Tx,const Ty) const{return x-y;}
};int main(int argc,char* argv[]){plusintplus_obj{};minusintminus_obj{};//以下使用仿函数就像使用一般函数一样std::cout plus_obj(3,5) std::endl;std::cout minus_obj(3,5) std::endl;//以下直接产生仿函数的临时对象(第一对小括号)并调用之(第二对小括号)std::cout plusint()(3,5) std::endl;std::cout minusint()(5,3) std::endl;
} 请使用手机扫一扫x