STL标准模版库
文章平均质量分 81
记录学习stl源码编程过程。。。
slowlytalk
正经程序员.
展开
-
stl使用中的经验(十八)--使用函数对象作为算法的参数
使用高级语言编写程序的缺点是,越抽象,代码的效率越低。例如下面的例子,我们将一个由小到大的存储10000000个double类型的vector调用sort算法排序,并且让他的顺序改为由大到小。typedef vector<double> DVec;typedef vector<double>::iterator DVecIter;DVec dv;clock_t t1 = clock();cout << "time 1 " << t1 <&l原创 2021-12-20 22:28:49 · 496 阅读 · 0 评论 -
stl使用中的经验(十七)--查找算法count/find/binary_search/lower_bound/upper_bound和equal_range
很多时候,我们都能遇到在一对迭代器标识的区间中查找一些信息,stl提供了比较多的查找算法,而我们也要根据不同的情况选择不同的算法进行查找,但基于的目的总是快速、简单和高效。这样也就有了我们在选择具体的查找策略时,指定的区间是否排序是选择算法的一个至关因素。如果区间是排序的,那么选择binary_search/lower_bound/upper_bound和equal_range(运行时间是对数)则能够获得更快的效率。但如果不是排序的,那就只能在count、find及其衍生算法(线性时间消耗)中选择。虽然原创 2021-12-17 00:32:28 · 1021 阅读 · 0 评论 -
stl使用中的经验(十六)--算法调用优于手写循环
每一个算法都至少需要使用一对迭代器来指定一个对象区间。算法的操作也是在这个区间上运行,算法是要在这个区间上,检查每一个对象,是否满足自己的期望。因此,算法的本质就是运行一个简单的循环,在指定的区间内遍历每一个对象,并对对象做出自己期望的检查或者调用。但并不是所有的算法都会完整的遍历完整个区间,比如,find和find_if。这两个算法,如果在区间的某个位置找到了自己想要找的对象,则会直接返回。但无论如何,它还是进行了小循环的遍历。只有当他遍历完区间中所有的对象后,他才会知道我们想要找的对象并不存在。如原创 2021-12-10 01:15:05 · 565 阅读 · 0 评论 -
stl使用中的经验(十五)-- 确保less<T> 和 operator< 有相同的语义
我们都知道,stl容器中的是有默认的排序函数的,默认排序less<T>,一般都是按照大小排序的。如果存储的是自定义的元素,并且假设我们的排序因子有多个,则主要是看我们自定义类中的 operator< 函数是怎么书写的。我们首先看个例子。#include <iostream>#include <set> #include <algorithm> #include <iterator>using namespace std;cla原创 2021-11-28 20:01:13 · 407 阅读 · 0 评论 -
stl使用中的经验(十四)--ptr_fun、mem_fun、mem_fun_ref
首先我们看个例子。#include <iostream>#include <vector> #include <algorithm> #include <iterator>using namespace std;class Widget{ public: Widget(int a) : m_a(a) { } int value() const { return m_a; } bool test() { retur原创 2021-11-28 19:54:52 · 888 阅读 · 0 评论 -
stl使用中的经验(十三)--若类是一个函数子,则应使它可配接
我们先看一个例子:#include <iostream>#include <vector> #include <algorithm> #include <iterator>using namespace std;class Widget{public: Widget(int a) : m_a(a) { } int value() const { return m_a; }private: int m_a{0}; }原创 2021-11-28 19:45:25 · 599 阅读 · 0 评论 -
stl使用中的经验(十二)--确保判别式是纯函数
我们先看两个概念:判别式:是一个返回bool类型(或者可以隐式的转换为bool类型,比如 int)的函数。纯函数:是指返回值仅仅依赖于其参数的函数。比如:假设f是一个纯函数,x,y是其参数,f(x,y)的返回值只有当x或y的值发生改变的时候才会发生改变。所以在C++中,纯函数所能访问的数据仅限于参数以及常量(在函数生命周期内不会被改变)。判别式类,是一个函数子,其operator()函数是一个判别式。也就是说,他的operator()函数返回true或者false。stl中能接受一个真正的判别原创 2021-11-21 14:49:32 · 472 阅读 · 0 评论 -
stl容器使用中的经验(十一)--erase-remove删除存储指针的容器元素
我们首先看个例子。#include <iostream>#include <vector> #include <list>#include <algorithm>using namespace std;class Widget{public: Widget(int a) : m_a(a) { if(a % 2 == 0) { m_isMeasured = true; } } bool isMeasured() {原创 2021-10-26 23:39:26 · 1042 阅读 · 0 评论 -
stl容器使用中的经验(十)--remove并不能删除容器中的元素,要结合erase方法使用
在我们刚开始接触stl标准容器的时候,或者说只是看了某些方法的字面意思就对该方法的作用进行一些猜测,这样其实是有很大缺陷的,比如今天要说的remove方法,看字面意思,我们很容易理解为是从容器中删除什么。但其实呢?我们先看下remove方法的申明和定义。template <class _ForwardIter, class _Tp>_ForwardIter remove(_ForwardIter __first, _ForwardIter __last, const _Tp& __原创 2021-10-21 22:44:16 · 346 阅读 · 0 评论 -
stl容器使用中的经验(九)--确保容器的目标容量足够大
stl容器在有新元素插入(insert、push_back、push_front等)进来的时候,它会自动的扩充存储空间用来存储这些新元素。但所有的情况下都是这样的吗?我们来看一个例子。#include <iostream>#include <vector> #include <algorithm>using namespace std;int transmogrify(int x){ return ++x;}int main(){ typed原创 2021-10-21 22:32:41 · 191 阅读 · 0 评论 -
stl容器使用中的经验(八)对于逐个字符的输入请考虑使用 istreambuf_iterator
先来看个例子:ifstream inputFile("ints.dat");list<int> data(istream_iterator<int>(inputFile), istream_iterator<int>());上面的这两行代码,貌似是将两个 isteam_iterator 迭代器传给list容器的构造函数,从而将文件中的数据拷贝到容器中。但是,结果真的如我们所料吗?首先我们看下下面的代码。int f(double d);int f(double原创 2021-10-19 22:34:12 · 320 阅读 · 0 评论 -
stl容器使用中的经验(七)--iterator 优于 const_iterator、reverse_iterator、const_reverse_iterator
1、iterator 优于 const_iterator、reverse_iterator、const_reverse_iterator一般来说,标准stl容器都提供了4中迭代器。对于一个容器container<T>而言,iterator相当于 T* ,const_iterator相当于 const T*;我们以map为例,其他的容器也大差不差的实现了下面三个函数的功能。iterator insert(iterator position, const value_type& __x)原创 2021-10-16 08:31:44 · 700 阅读 · 1 评论 -
stl容器使用中的经验(六)--考虑 map::opreator[]和map::insert()的效率问题
结论 :当效率至关重要时,如果要更新一个容器的值,优先选择map::operatot[],如果需要插入一个新的元素,则优先选择map::insert()。假设定义如下类:class Widget{public: Widget(); Widget(const double& val); Widget& opeartor=(double val); ...}创建一个从int到map的映射容器。std::map<int, Widget>原创 2021-10-11 22:31:40 · 474 阅读 · 0 评论 -
stl容器使用中的经验(五)--不要随意修改set或者multiset的键
1、不要随意修改set或者multiset的键对map和multimap来说,直接修改键会在编译器这一层报错。map<_key, _value> m;m.bengin()->first = 10; //编译失败主要是因为对于map和multimap来说,他们的元素类型是pair<const _Key, _Tp>也就是说,_Key是const类型的,不允许修改。而对set或multiset来说,他们的元素的类型是 _Key,而不是const _Key的。为原创 2021-10-10 15:55:00 · 141 阅读 · 0 评论 -
stl容器使用中的经验(四)--关联容器实现自己的比较类型及比较函数在等值的情况下一定要返回false
1、关联容器实现自己的比较类型我们经常定义一个容器。vector<int> vec;其实,这个是下面函数的缩写。vector<int, less<int>> vec;vector<int, less<int>, allocator<int>> vec;只不过是默认的,容器中指定了默认的比较大小的函数和分配子。当然这主要是对关联容器来说的,因为序列容器是有顺序的。但是如果我们在容器中存入的是指针,并且对输出有一定的顺序原创 2021-10-07 14:32:48 · 171 阅读 · 0 评论 -
stl容器使用中的经验(三)--swap函数的使用
1、怎样将vector和string传给旧的CAPI怎样将vector当作一个数组来使用,在C++标准化后,我们都致力于使用vector来代替数组,但不可不承认的是,老的C版本的API还是存在的,那么我们怎么用vector来当作是数组来用。简单的,看一个简单的例子。void doSomething(const int* p, size_t size)如果我们想将vector传入上面的函数,则vector<int> vec;doSomething(&vec[0], vec.s原创 2021-10-05 11:17:03 · 676 阅读 · 2 评论 -
stl容器使用中的经验(二)--如何正确删除容器的元素和使用reserve减少内存分配次数
1、慎重选择删除元素的方法或许我们曾遇到过一道面试题,给定一个vector矢量,删除这个容器中所有值等于3的元素。第一次,手写循环删除:vector<int> vec{1, 2, 3, 5, 3, 6, 3, 7, 3, 3};for(vector<int>::iterator iter = vec.bengin(); iter != vec.end(); ++iter){ if((*iter) == 3) { iter = vec.ears原创 2021-10-04 12:01:52 · 346 阅读 · 0 评论 -
stl容器使用中的经验(一)--stl容器的选择和基本概念
1、关于容器的两个概念1、连续内存容器(基于数组的容器)将其元素放在一块或多块(动态分配)的内存中,每块内存中有多个元素。当有新元素插入或者已有元素删除时,统一内存块中的其他元素要向前或向后移动,以便为新元素让出空间,或者填补删除元素的空间。这种移动会影响效率和异常安全,标准的连续容器:vector list deque。2、关联容器(基于节点的容器)基于节点的容器在每一个(动态分配)内存块上只存储一个元素。元素的插入和删除只会影响指向节点的指针,并不会影响节点本身的内容。因此当插入或者删除时,元素原创 2021-10-03 22:45:39 · 282 阅读 · 0 评论 -
stl标准库系列之--queue
我们在前面说stack的时候已经说过了什么叫容器适配器,如果有不了解的,可以去前面看一看。这里呢,我们主要讲下queue,作为生活里面我们司空见惯了的现像,应该是不叫好理解的。1、queue容器的定义和 stack 栈容器适配器不同,queue 是一种先进先出(FIFO)的数据结构,queue 容器适配器有 2 个开口,其中一个开口专门用来输入数据,另一个专门用来输出数据。但是queue元素的加入和取出是固定的,比如加入只能在队尾加入,取出只能在队前,其他地方都不能进行元素的操作。简单的说,queue原创 2021-05-16 17:12:38 · 1529 阅读 · 0 评论 -
stl标准库系列之--stack
1、什么是容器适配器2、stack 容器的定义3、stack 容器创建1、 创建一个不包含任何元素的 stack 适配器,并采用默认的 deque 基础容器2、创建指定底层容器的 stack 适配器3、赋值4、迭代器5、成员函数6、使用1、什么是容器适配器理解容器适配器之前,我们需要了解什么是适配器,其实和我们现实中的适配器是差不多的理解。也可以去了解下设计模式中的适配器模式。容器适配器是一个封装了序列容器的类模板。是在一般的序列容器的基础上提供了一些功能。所谓的容器适配器,目的就是为了适配基础容器.原创 2021-04-25 23:50:11 · 588 阅读 · 0 评论 -
stl标准库系列之--deque
1、概述deque 是 double-ended queue 的缩写,又称双端队列容器。是由一段一段的定量连续空间构成,可以向两端发展,因此不论在尾部或头部安插元素都十分迅速。 在中间部分安插元素则比较费时,因为必须移动其它元素。我们看下deque的示意图。2、与vector的区别vector是单向开口的连续性空间,deque则是双向开口的连续空间(连续是假象)。deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间添加或删除元素。vector扩容时经历了原创 2021-04-21 03:30:32 · 652 阅读 · 2 评论 -
stl标准库系列之--map
1、概述map是一个关联式容器,所谓的关联式容器,也就是类似与关联性数据库。每个元素都有一个键(key)和一个值(value)一一对应。关联式容器一般都是默认进行排序的。排序规则是按照键值的大小。容器的内部结构一般为 RB-tree,或者hashtable。映射和多重映射基于某一类型Key的键集的存在,提供对T类型的数据进行快速和高效的检索。键和值的数据类型一般是不一致的。是一个pair类型中的两个分量。所有类型的 map 容器保存的都是键值对类型的元素。map 容器的元素是 pair<cons原创 2021-04-10 21:37:43 · 1314 阅读 · 0 评论 -
stl标准库系列之--list
1、概述2、节点 node3、定义4、特点5、创建方法6、内存管理7、成员函数8、迭代器1、概述list 容器,是序列容器的一种,是一个双向链表,因此又被称作双向链表容器。相较于vector的连续性空间来说,list会显得比较复杂。即该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中。可以看到,list 容器中各个元素的前后顺序是靠指针来维系的,每个元素都配备了 2 个指针,分别指向它的前一个元素和后一个元素。其中第.原创 2021-03-23 23:16:03 · 365 阅读 · 0 评论 -
stl标准库系列之--vector
1、概述2、定义3、特点4、创建方法5、内存管理1、概述了解vector之前,我们先了解一下C++的普通数组,在C++11之后,新增了array序列容器。array实现的是静态空间,也就是说,只要配置了空间就不能随心所欲的改变了。如果现在家里人口增多了,房子不够住了,需要建造 更大的房子了。需要先在比较大的地方先造好房子,然后将原先房子里面的东西都搬过去。以前的旧房子也就没什么必要了,必要的时候就可以推倒干点别的。比如说,建个养马场~~vector 容器是 STL 中最常用的容器之一,它和 arra.原创 2021-03-19 00:24:21 · 1414 阅读 · 0 评论 -
STL标准库系列之--相关概念
前言在学习STL编程的前提,是需要了解C++模板的概念。模板是C++程序设计语言中的一个重要特征,而标准模板库正是基于此特征。标准模板库使得C++编程语言在有了同Java一样强大的类库的同时,保有了更大的可扩展性。1、什么是STLSTL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISO C++原创 2021-03-16 17:04:10 · 191 阅读 · 0 评论