C++标准库(体系结构与内核分析)

一、C++标准库介绍

C++标准库:C++ Standard Library

C++标准库与STL有什么关系:

  STL:Standard Template Library

  STL包含6大部件,基本占标准库的80%左右内容,而另外20%是一些好用的零碎的东西,所以说C++标准库包含STL。

  • 编译器一定带着一个C++标准库,是以头文件(header files)的形式提供的,并不是编译好的文件,而是源代码。
  • C++标准库的头文件不带扩展名(.h),例如#include <vector>。
  • 对于C语言的标准库,新式的C语言标准库头文件也去除了扩展名(.h),例如#include <cstdio>。
  • 对于某些编译器,旧式的头文件也可以使用,例如#include <stdio.h>。
  • 新式头文件内的组件都封装在命名空间(namespace)std中,例如using namespace std;

常用写法:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
//打开std命名空间
using namespace std;

二、STL六大部件

STL的六大部件分别是:

  • 容器:Containers
  • 分配器:Allocator
  • 算法:Algorithms
  • 迭代器:Iterator
  • 适配器:Adapters
  • 仿函数:Functors

其中容器和算法是最重要的两大部件。以前有句老话叫做“数据结构加算法就等于程序”,在这句话中,容器就是数据结构,是一个优秀的团队将常用的数据结构都在STL中实现了。同样的,常用算法也在STL算法部件中实现。所以掌握了C++标准库的时候,可以避免重复造轮子的问题,而且库中提供的功能都经过无数次的优化,性能有很好的保证。

六大部件简要介绍:

容器:容器是一堆常用数据结构的实现,主要用户存放和读取数据,屏蔽了底层的内存分配和释放的问题,所以能够让用户更方便和高效的使用。

分配器:容器对数据结构的封装,要处理内存分配和释放的问题,就用到了分配器。

算法:既然容器用来存取数据,相当于一个数据的仓库,那么算法就是用来处理这些数据的工具。在STL中,算法和容器是分开设计的,这和面向对象(OO)有点不符,在面向对象中,我们一般将数据和方法封装在一个类中,而在STL中,使用的是模板式编程,是另外一条路线。

迭代器:我们的算法要操作容器中的数据。如何将两者结合起来,就需要一个桥梁,这个桥梁就是迭代器。迭代器可以看成是一种泛化的指针。

仿函数:比较抽象,后面解释。

适配器:用于做一些转换,例如容器适配器、仿函数适配器、迭代器适配器。

三、六大部件示例

上图中程序解释:(其中将六大部件综合在一起展示)

1.在第11行,定义一个容器vector,模板参数为<int, allocator<int>>,其中第一个int代表vector要装的数据类型,后面的allocator<int>是一个内存分配器,用于vector的内存分配。这个分配器是一个可选项,如果不写,标准库源码中有一个默认的分配器给vector,分配器也是一个模板,模板参数必须和容器的第一模板参数匹配,这里是int。

2.定义vector变量vi,构造函数选用的是将数组ia的第一个位置和最后一个位置作为参数。

3.在第13行,选用了一个叫做count_if()的算法来处理容器vi。这个算法的作用是对vi中满足一定条件的元素进行计数。

4.count_if()的参数分别是指向容器开头的迭代器(泛化指针)、指向容器结尾的迭代器以及对元素的过滤条件。vi.begin()返回的是指向开头的迭代器,vi.end()返回的是指向结尾的迭代器。

5.less<int>()是一个仿函数,用于比较大小。

6.bind2nd(less<int>(), 40)是一个适配器,意思是将第二个参数也就是整数40,绑定到less<int>()。意思就是小于40的整数。

7.not1()函数也是一个适配器,意思是取反义,也就是将小于40,变为大于等于40。

8.最后的输出就是vi中大于等于40的元素的个数,结果为4。

四、算法效率介绍

每个人都想用效率最高的东西和方法,那位什么标准库还要提供十个八个容器和一大堆算法呢?

因为每个人的需求不同,例如数据分布、数据排列方式、数据处理需求都不一样。没有一个特定的容器或算法能够适应所有的需求。所以我们必须根据不同的需求来选择不同的容器和算法。

如何评价容器或算法的效率,我们经常会使用复杂度(Complexity)或O()(big-oh)来衡量。

主要的复杂度有以下一些:

1.O(1)或O(c):常数时间(constant time)

2.O(n):线性时间(linear time)

3.O(log2n):以2为底n的对数,次线性时间(sub-linear time)

4.O(n2):n的平方,平方时间(quadratic time)

5.O(n3):n的立方,立方时间(cubic time)

6.O(2n):2的n次方,指数时间(exponential time)

7.O(nlog2n):介于线性与平方的中间模式。

这里面的n必须是一个很大的数(几十万甚至更大)才有实际的意义,因为当n很大时,各个复杂度之间的效率千差万别。而如果n很小,例如一些玩具程序,那对于计算机的计算速度,效率之间差距就没什么意义了。

五、区间表示法

我们对一个范围的表示一般有三种方式:

1.[  ]:闭区间,即包含前后的元素。

2.(  ):开区间,即前后元素都不包含。

3.[  ):前闭后开区间,即包含前面的元素,不包含后面的元素。

在C++标准库中,选择第3种作为区间表示,也就是前闭后开

如上图所示,c是一个容器对象,c.begin()返回一个迭代器(泛化指针),这个迭代器指向容器的第一个元素的地址。c.end()也返回一个迭代器,这个迭代器指向容器最后一个元素后下一个地址,但是那个地址所保存的东西,根本不是这个容器所拥有的。所以,使用*(c.end())所取到的数据是没有意义的(可能导致程序崩溃)。

上图中展示了如何使用迭代器和for循环来遍历容器中的元素。代码如下:

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//定义容器,将数组arr的数据放入容器中
vector<int> vi(arr, arr + 10);
//获取容器开头的迭代器
vector<int>::iterator bg = vi.begin();
//当bg不等于vi.end()时,也就是说还有滑到容器的最后,打印bg指向的数据,并滑向下一个位置
for (; bg != vi.end(); bg++) {
    cout << *bg << endl;
}

另一种遍历的做法(C++11新特性):(参照笔记:C++程序设计2里的第十四节 基于range的for循环)

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//定义容器,将数组arr的数据放入容器中
vector<int> vi(arr, arr + 10);
//使用auto可以让编译器自己推导类型,当然也可以写for(int i : vi){}
for (auto i : vi) {
    cout << i << endl;
}

原文地址:https://www.cnblogs.com/leokale-zz/p/11100566.html

时间: 2024-10-09 14:07:22

C++标准库(体系结构与内核分析)的相关文章

C++ 异常机制分析(C++标准库定义了12种异常,很多大公司的C++编码规范也是明确禁止使用异常的,如google、Qt)

阅读目录 C++异常机制概述 throw 关键字 异常对象 catch 关键字 栈展开.RAII 异常机制与构造函数 异常机制与析构函数 noexcept修饰符与noexcept操作符 异常处理的性能分析 正文 回到顶部 C++异常机制概述 异常处理是C++的一项语言机制,用于在程序中处理异常事件.异常事件在C++中表示为异常对象.异常事件发生时,程序使用throw关键字抛出异常表达式,抛出点称为异常出现点,由操作系统为程序设置当前异常对象,然后执行程序的当前异常处理代码块,在包含了异常出现点的

C 标准库IO缓冲区和内核缓冲区的区别

1.C标准库的I/O缓冲区 UNIX的传统 是Everything is a file,键盘.显示器.串口.磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也可以像普通文件(保存在磁盘上的文件)一样打开.读.写和关闭,使用的函数接口是相同的.用户程序调用C标准I/O库函数读写普通文件或设备,而这些库函数要通过系统调用把读写请求传给内核 ,最终由内核驱动磁盘或设备完成I/O操作.C标准库为每个打开的文件分配一个I/O缓冲区以加速读写操作,通过文件的FILE 结构体可以找到这

C++标准库分析总结(五)——&lt;Deque设计原则&gt;

本节主要总结标准库Deque的设计方法和特性以及相关迭代器内部特征 1.Deque基本结构 Deque(双向队列)也号称连续空间,其实它使用分段拼接起来的(分段连续),各个分段间是用Vector来管理的,Vector的每个元素就是一个指针,每个指针指向一个分段,每一个分段就是一个缓冲区buffer,首位安插元素时,当缓冲区满了需要扩充时,就重新分配一个缓冲区然后串在Vector里面: Deque的迭代器有4个指针,其中node表示在控制中心的位置(也就是在Vector中的位置),first表示n

LINUX内核分析第七周学习总结——可执行程序的装载

LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.知识概要 (一)预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 2.目标文件的格式ELF 3.静态链接的ELF可执行文件和进程的地址空间 (二)可执行程序.共享库和动态加载 1.装载可执行程序之前的工作 2.装载时动态链接和运行时动态链接应用举例 (三)

Linux内核分析期末总结

<Linux内核分析>期末总结 20135313吴子怡.北京电子科技学院 Chapter1 往期博客传送门 (1)计算机是如何工作的:Linux内核分析——第一周学习笔记 (2)操作系统是如何工作的:Linux内核分析——第二周学习笔记 (3)Linux系统启动过程:Linux内核分析——第三周学习笔记 (4)系统调用的方法: Linux内核分析——第四周学习笔记 Linux内核实验作业四 (5)分析system_call中断处理过程: Linux内核分析——第五周学习笔记 实验作业:使gdb

20135327郭皓--Linux内核分析第七周 可执行程序的装载

第七周 可执行程序的装载 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一.预处理,编译,链接和目标文件格式 1.可执行程序是怎么得来的 c代码->预处理->汇编代码->汇编器->目标代码->链接成可执行文件->加载到内核执行 2.目标文件的格式ELF 符号修饰标准.变量内层布局.函数调用方式等这些跟可执行代码二进制兼容性相关的内容称为ABI

20135201李辰希 《Linux内核分析》第七周 可执行程序的装载

李辰希  原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 编译链接的过程 1.预处理阶段 gcc -E -o XX.cpp XX.c -m32 XX.cpp是预处理文件 2.编译器生成汇编代码阶段 gcc -x cpp-output -S -o hello.s hello.cpp -m32 XX.s是汇编代码 3.汇编器

内核分析-第五周

刘文学 原创作品转载请注明出处 http://blog.csdn.net/wdxz6547/article/details/50993837<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 预备知识 内核态 用户态 为什么要划分系统级别? 如何区分内核和用户态? cs:eip 寄存器上下文 上下文切换 系统调用号 中断向量 调度时机 系统调用过程中一定发生中断, 在系统调用执行过程中可能有进程的切换. 系统调用分

c运行库、c标准库、windows API的区别和联系

C运行时库函数C运行时库函数是指C语言本身支持的一些基本函数,通常是汇编直接实现的.  API函数API函数是操作系统为方便用户设计应用程序而提供的实现特定功能的函数,API函数也是C语言的函数实现的. 区别他们之间区别是:API函数是针对操作系统的,C语言运行时函数则是针对C语言本身的. ·1.运行时库就是 C run-time library,是C而非C++语言世界的概念.     取这个名字就是因为你的C程序运行时需要这些库中的函数. ·2.C语言是所谓的“小内核”语言,就其语言本身来说很