C++候捷stl-视频笔记1

认识headers、版本、重要资源

STL的核心思想是泛型编程

新式头文件内的组件封装在命名空间std中:
using namespace std;
using std::cout;或std::vector vec;
旧式头文件内的组件不封装在命名空间std中

注:不建直接使用using namespace xxx,如果使用的头文件有被外部文件引用,有命名冲突的风险。建议打开具体的使用对象,如using std::cout;,或者使用时打开std::string a;
http://www.cplusplus.com/
https://en.cppreference.com/w/
http://gcc.gnu.org/

STL体系结构基础介绍

STL六大部件::
容器:放数据的模版类,帮我们解决掉内存的问题
分配器:是来支持容器将数据放到内存里
算法:是一个个函数来处理存放在容器里的数据,一种模版函数(模版编程,与oop不同,操作数据的函数与数据不在一起)
迭代器:一套访问容器的接口,类似泛化的指针
仿函数:作用类似函数,例如相加相减等等
适配器:有三种,分别将容器,迭代器,仿函数来进行一个转换
在这里插入图片描述
在这里插入图片描述
allocator 是分配器(一般忽略),vector 是容器,count_if 是算法
vi.begin() 是迭代器
not1,bind2nd是适配器
less 是仿函数

判断条件 predicate 为:not1(bind2nd(less(), 40)) —— 表示 >= 40 数为真(小于40的否定)

容器为前闭后开区间
在这里插入图片描述

容器之分类与各种测试

序列式容器:按照元素的存储顺序依次排列
Array:容量大小固定
Vector:单端进出,容量大小可动态扩展
Deque:双端可进可出
List:双向循环链表,不连续
Forward-List:内存占用少于双向链表
关联式容器:包括键和值,适合快速查找
集合(Set/Multiset):由红黑树(高度平衡二叉树)实现,key就是value,value就是key。mult元素可重复
映射表(Map/Multimap):由红黑树(高度平衡二叉树)实现。mult键值可重复
不定序容器:底层使用哈希表实现。
无序集合(Unordered Set/Multiset):由哈希表实现
无序映射表(Unordered Map/Multimap):由哈希表实现
哈希表包括若干个bucket,每个bucket对应一个链表。哈希冲突时,应避免每个bucket对应的链表长度过长而导致元素搜索时间较长
在这里插入图片描述
Array50万个元素,随机填充容器47ms, 0-32767查找20000,排序和搜索187ms(二分查找前需排序)
vector:push_back100万个元素。每次push_back申请的空间以两倍增长,会申请预留空间。size是大小,capacity是申请的内存空间大小;是另外找一个两倍大的空间。可能出现申请内存空间不足,需要try,catch抓取异常。 随机数据填充容器:3063ms;直接搜索,次序查找:0ms(搜索时间看运气,运气很好);排序后二分查找:2765ms。
listpush_back100万个元素。随机数据填充容器:3265ms;直接搜索:16ms;排序:2312ms。 c.sort(); 是容器自带的排序函数,如果容器自带肯定是要比全局的排序函数好的
forward_list:forward_list 只有 c.push_front(); 且没有 forward_list.back() forward_list.size()。100万个元素。随机数据填充容器:3204ms;直接搜索:15ms;排序:2656ms
deque:类似vector,两边都能扩充,实际上是分段连续的。其是通过 map(是一个vector,但在扩充时会 copy 到中间)里的指针指向各个 buffer,buffer 里再存数据,每个 buffer 的大小一致,每次扩充都是扩充一个指针指向一个新的 buffer。随机数据填充容器:2704ms;直接搜索:15ms;排序:3110ms
(关联性容器查找都非常快)
栈stack和队列queue底层依赖于deque容器,由于其没有自己的数据结构,因此不把stack和queue作为容器,而作为容器适配器;
在这里插入图片描述
在这里插入图片描述
multiset:有自己提供用于查找的find()函数时,效率更高。insert自动排序,底层结构是红黑树。随机数据填充容器:6609ms(其在填充的时候就进行排序了);直接搜索 ::find():203ms;c.find():0ms
multimap:multimap.inset(pair<int,string>),要自己组合pair<int,string>元素放进去。随机数据填充容器:4812ms(其在填充的时候就进行排序了);c.find():0m
unordered_multiset:bucker_count()篮子数量,篮子一定比元素多,每个篮子的链表不能太长(经验法则:当元素个数大于等于bucket个数时,bucket个数会扩充至约原先的2倍。)。bucket_size()可以看篮子里有多少数量。随机数据填充容器:4406ms;直接搜索 ::find():109ms;c.find():0ms;前二十个 bucket 中只有一个有24个元素
unordered_multimap与unordered_multiset类似
set:key就是value,value就是key,插入重复的值,不会增长元素
map:[]会自动合成Pair格式

分配器之测试

容器需要分配器allocator作为支撑;每个容器类都有默认的容器分配器allocator(模板参数使用默认值)。

template<typename _Tp, typename _Alloc = std::allocator<_Tp>>	// 使用默认参数
class vector : protected _Vector_base<_Tp, _Alloc>
    
template<typename _Tp, typename _Alloc = std::allocator<_Tp>>	// 使用默认参数
class list : protected _List_base<_Tp, _Alloc>
    
template<typename _Tp, typename _Alloc = std::allocator<_Tp>>	// 使用默认参数
class deque : protected _Deque_base<_Tp, _Alloc>
    
template<typename _Key, typename _Compare = std::less<_Key>,
			typename _Alloc = std::allocator<_Key>>
class set ...
    
template<typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
			typename _Alloc = std::allocator<std::pair<_Key, _Tp>>
class map ...
    
template<class _Value, class _Hash = hash<_Value>, 
			class _Pred = std::equal_to<_Value>, class _Alloc = std::allocator<_Value>>
class unordered_set ...
    
template<class _Key, class _Tp, class _Hash = hash<_Key>, 
			class _Pred = std::equal_to<_Key>,
			class _Alloc = std::allocator<std::pair<_Key, _Tp>>
class unordered_map ...

在这里插入图片描述
不建议手动使用分配器直接管理内存 allocate()和deallocate()函数释放内存时需释放指针和对应大小的内存。

面向对象编程(OOP) vs. 泛型编程(GP)

OOP=数据+操作,OOP是想要把data和method关联在一起打包

// list容器的迭代器不支持随机访问
template <class T, class Alloc = alloc>
class list {
    ...
    void sort();	// list容器类的成员函数sort()
};

标准库中很少有继承关系,因此虚函数很少,关系比较简单

GP是将data和methods分开来
容器类

// vector容器的迭代器支持随机访问
template <class T, class Alloc = alloc>
class vector {
    ...
};

// deque容器的迭代器支持随机访问
template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque {
    ...
};

Alogorithm是全局函数

/* STL标准库提供的全局::sort() */
// ::sort(c.begin(), c.end())
template <class RandomAccessIterator>	// 随机访问迭代器
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {
	...
}

template <class RandomAccessIterator, class Compare> // 比较规则
inline void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp) {
	...
}

Containers和Alogorithm可以各自闭门造车,然后以iterator联通既可
Alogorithm通过Iterator确定操作范围,并通过Iterators取用Continer元素;

/* max函数的重载 */
template <class T>
inline const T& max(const T& a, const T& b) {
    return a < b ? b : a;
}

// Compare 自定义的比较规则
template <class T, class Compare>
inline const T& max(const T& a, const T& b, Compare comp) {
    return comp(a, b) ? b : a;
}

在标准库中操作符重载变得至关重要

为什么list不能使用::sort()排序?
List的迭代器不能跳来跳去,不能随机访问,只能一个一个往前跳,不能直接+5,-5;标准库sort()所用到的随机访问迭代器,而list迭代器不足以达到要求;
在这里插入图片描述

所有Algorithms,其内最终设计元素本身的操作,无非就是比大小

技术基础:操作符重载and模板(泛化,全特化,偏特化)

操作符重载示例
在这里插入图片描述
类模版
调用者在使用时再指定泛型的具体类型。

template<typename T>	// 类模板
class complex{
private:
    T re, im;	// 模板
    friend complex& __doap1 (complex *ths, const complex& r); 	// 友元函数
public:
    complex(T r = 0, T i = 0) : re(r), im(i){}	// 默认参数、初始化列表
    complex& operate+=(const complex&);	// 重载运算符
    T real() const { return re; }		// 成员函数-常函数
    T imag() const { return im; }
};

类模板使用时,需显式指定具体的泛型类型。编译器不会对类模板进行类型推导

{
    complex<double> c1(1.1, 2.2);
    complex<int> c2(3, 4);
}

函数模版
class可替换为typename。
函数模板使用时,不必显式指定具体的泛型类型。编译器会对函数模板进行实参推导/类型推导(argument deduction)。类模板使用时,需显式指定具体的泛型类型。

// 函数模板
template<class T>
inline const T& min(const T& a, const T& b){
    return b < a ? b : a;
}
class stone{
public:
    stone(int w, int h, int we) : _w(w), _h(h), _weight(we){}
    bool operator< (const stone& rhs){
        return this->_weight < rhs._weight;
    }
private:
    int _w, _h, _weight;
}
int main(){
    stone r1(2, 3), r2(3, 3), r3;
    r3 = min(r1, r2);	
}

成员模版
类模板中的成员(函数/属性)也为模板
STL中的拷贝构造函数和有参构造函数常设计为成员模板
成员模板的泛型类型是类模板的泛型类型的子类。成员模板的泛型类型U1/U2,继承自类模板的泛型类型T1/T2。反之不成立。

class Base1 {};
class Derived1 : public Base1 {};
class Base2 {};
class Derived2 : public Base2 {};

pair</* U1 */Devired1, /* U2 */Devired2> p;
pair<Base1, Base2> p2(p);
/* 等价写法 */
// 使用成员模板创建匿名对象,用于类的拷贝构造函数
pair</*T1*/Base1, /*T2*/Base2> p2(pair</*U1*/Devired1, /*U2*/Devired2>());

如智能指针子类shared_ptr有参构造函数的参数(被包装的指针),是智能指针父类__shared_ptr有参函数构造函数的参数(被包装的指针)的子类。

template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
{
    ...
    /* 成员模板 */
    template<typename _Tp1>
    // 构造函数
    // 子类构造函数shared_ptr的参数__p,对父类构造函数__shared_ptr<_Tp>赋值
    explicit shared_ptr(/*Devired*/_Tp1* __p) : __shared_ptr</*Base*/_Tp>(__p) {}
    ...
};

/* 指针类的多态 */
Base1 *ptr = new Devired1;	// 向上转型up-cast
/* 智能指针类的多态 */
// 使用子类对象
shared_ptr<Base1*> sptr(new Devired1);	// 模拟向上转型up-cast

特化 specialization
泛化(generalization):使用时再指定模板参数的具体类型。
特化(specialization):将模板泛化的部分进行局部的特征化。显式指定部分或全部模板参数的具体类型
在这里插入图片描述
在这里插入图片描述
特化的优先级高于泛化。当存在合适的特化版本时,编译器优先调用相应的特化版本。
全特化的所有模板参数均被指定,故模板参数列表为空,即template <>。

全特化(full specialization):显式指定全部模板参数的具体类型。
偏特化/局部特化(partial specialization):指定部分模板参数的具体类型。

偏特化示例:两个模板参数,锁定其中一个
在这里插入图片描述
锁定范围的偏特化,如T是一个指针在这里插入图片描述

分配器

所有分配动作最终都会到malloc()函数
在这里插入图片描述
内存分配,蓝色是块是实际我们需要malloc给我们分配的空间,灰色的块是debug mode需要添加的内存空间,上下两个红色的块是cookie,它记录分配内存的大小(《深度探索c++对象模型》书上称为记录元素的大小,这个指的是delete时,该delete多大的内存空间,即delete掉的数组维度大小),绿色的部分指的是为了内存大小的对齐
vc6默认分配器allocators
在这里插入图片描述
VC6+的allocator只是以::operator new和::operator delete完成allocate()和deallocate(),没有任何特殊的设计
BC5编译器对于allocator分配内存和回收内存用的还是operator new和operator delete,底部还是用c语言的malloc和free完成,和VC6的实现一样

容器分配大量小的元素时,由于元素内存分配都用malloc,元素内存都很小,但额外开销很大。通常容器的元素都是较小的,因此额外开销比例较大,是不好接受的。

都是对malloc和free的各种包装,比起直接调用反而变慢了
在这里插入图片描述
GNU C++(G++) 2.9版本所附的标准库,allocator分配内存和回收内存用的还是operator new和operator delete,底部还是用c语言的malloc和free实现。但是自己的容器不用这个allcators,右下角说明这个分配器并没有被SGI STL header引入,即没有被使用
在这里插入图片描述
在这里插入图片描述
GC使用的是alloc分配器,核心诉求是尽量减少malloc的次数
共有16条链表,每一条链表负责特定大小的区块,编号为#0的链表负责大小为8B的内存块,编号为#1的链表负责大小为8 x 2 = 16B的内存块,编号为#3的链表负责大小为8 x 3 = 24B的内存块,…,以此类推,每次增加8B。每一条链表都是一次用malloc分配的一大块内存(带cookie),然后切分成小的标准块(不带cookie),当容器需要内存的时候,alloc就会按照需要的大小(变成8B的倍数)在链表中查找进行分配,这样实现在分配小块的时候就不需要存储cookie的开销了

G++4.9又不再使用alloc分配器,而是继续调用operator new 和operator delete
在这里插入图片描述
G++4.9的__pool_alloc就是G++2.9版本的alloc分配器
用例

vector<string, __gnu_cxx::__pool_alloc<string>> vec;// __gnu_cxx是一个命名空间

容器之间的实现关系与分类

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

apexcharts数据可视化之极坐标区域图

apexcharts数据可视化之极坐标区域图 有完整配套的Python后端代码。 本教程主要会介绍如下图形绘制方式&#xff1a; 基础极坐标区域图单色极坐标区域图 基础极坐标区域图 import ApexChart from react-apexcharts;export function BasicPolar() {// 数据序列const series…

深入解析多维数组与主对角线元素之和

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;多维数组的奥秘 二、多维数组的基本概念 1. 定义与创建 2. 维度与形…

Linux服务器安装docker,基于Linux(openEuler、CentOS8)

本实验环境为openEuler系统(以server方式安装)&#xff08;CentOS8基本一致&#xff0c;可参考本文) 目录 知识点实验 知识点 Docker 是一个开源的应用容器引擎。它允许开发者将应用及其所有依赖项打包到一个可移植的容器中&#xff0c;并发布到任何支持Docker的流行Linux或Wi…

歌曲转换成mp3格式超简单!快来试试看

在数字音乐时代&#xff0c;我们经常从各种来源下载或收藏到各种音频文件&#xff0c;但有时这些文件可能并不是我们设备所支持的常见格式&#xff0c;尤其是当我们更倾向于使用MP3格式的时候。因此&#xff0c;对于那些希望统一音乐库格式的人来说&#xff0c;将歌曲转换成mp3…

redis面试知识点

Redis知识点 Redis的RDB和AOF机制各是什么&#xff1f;它们有什么区别&#xff1f; 答&#xff1a;Redis提供了RDB和AOF两种数据持久化机制&#xff0c;适用于不同的场景。 RDB是通过在特定的时刻对内存中的完整的数据复制快照进行持久化的。 RDB工作原理&#xff1a; 当执行…

深入理解深度学习中的激活层:Sigmoid和Softmax作为非终结层的应用

深入理解深度学习中的激活层&#xff1a;Sigmoid和Softmax作为非终结层的应用Sigmoid 和 Softmax 激活函数简介Sigmoid函数Softmax函数 Sigmoid 和 Softmax 作为非终结层多任务学习特征变换增加网络的非线性实际案例 注意事项结论 深入理解深度学习中的激活层&#xff1a;Sigmo…

探索研究大语言在生物识别技术——使用ChatGP-4从完成从人脸识别到年龄估计

0.引言 论文提出以下几要点&#xff1a; &#xff08;1&#xff09;. 人脸识别、性别检测和年龄估计的性能评估&#xff1a; 进行了一项研究&#xff0c;使用GPT-4这样的大型语言模型来处理人脸识别、性别检测和年龄估计等任务。这些任务是生物识别技术中的常见应用&#xff…

【评测体验】OrangePi AIpro 系统构建及性能测试

感谢香橙派社区能够邀请我评测这款开发板&#xff0c;祝愿国产开发板发展越来越好&#xff01;在这里能够尽自己的一份力量是我的荣幸。 这篇文章是 OrangePi AIpro 开发板的评测&#xff0c;内容包括开发板简介、系统构建过程、系统性能测试、压缩算法性能测试、内核编译。 到…

分析和设计算法

目录 前言 循环不变式 n位二进制整数相加问题 RAM模型 使用RAM模型分析 代码的最坏情况和平均情况分析 插入排序最坏情况分析 插入排序平均情况分析 设计算法 分治法 总结 前言 循环迭代&#xff0c;分析算法和设计算法作为算法中的三个重要的角色&#xff0c;下面…

【深度 Q 学习-01】 Q学习概念和python实现

文章目录 一、说明二、深度 Q 学习概念三、python实现四、结论 关键词&#xff1a;Deep Q-Networks 一、说明 在强化学习 &#xff08;RL&#xff09; 中&#xff0c;Q 学习是一种基础算法&#xff0c;它通过学习策略来最大化累积奖励&#xff0c;从而帮助智能体导航其环境。它…

2024年618网购节各大电商超级红包二维码集合

一年一度的电商618网购节又要来了&#xff0c;下面收集了淘宝/京东/拼多多的618红包二维码&#xff0c;手机扫描或识别即可每天领红包&#xff0c;可参考好物分享中的商品下单&#xff1a; 淘宝618超级红包&#xff1a;即日起至2024.6.10&#xff0c;每天可领一次 京东618无门…

P9 【力扣+知识点】【算法】【二分查找】C++版

【704】二分查找&#xff08;模板题&#xff09;看到复杂度logN&#xff0c;得想到二分 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0…

RUST 和 GO 如何管理它们的内存

100编程书屋_孔夫子旧书网 Go 中的内存管理 Go 中的内存不会在缓存键被驱逐时立即释放。 相反&#xff0c;垃圾收集器会经常运行以发现任何没有引用的内存并释放它。 换句话说&#xff0c;内存会一直挂起&#xff0c;直到垃圾收集器可以评估它是否真正不再使用&#xff0c;而…

SpringCloud:Nacos配置管理

程序员老茶 &#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; P   S : 点赞是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#…

01--nginx基础

前言&#xff1a; 本文用来整理一下nginx的用法&#xff0c;应该是本人中间件专栏的第一篇文章&#xff0c;这里开始概念和实操将会同样重要&#xff0c;面试时基本概念的理解非常重要&#xff0c;深有体会&#xff0c;不会再让概念成为压死骆驼的稻草。 1、nginx简介 Nginx…

vue连接mqtt实现收发消息组件超级详细

基本概念&#xff1a; MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种基于发布/订阅模式的轻量级消息传输协议&#xff0c;专为低带宽、高延迟或不稳定的网络环境设计。以下是MQTT实现收发消息的基本原理&#xff1a; 客户端-服务器模型&#xff1a…

【数据结构】-- 栈

栈 引入&#xff1a; 一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的元素遵循先进后出的原则&#xff0c;先入栈的元素总是先后出栈。 压栈&#xff1a;栈的插入操作叫…

HCIP-Datacom-ARST自选题库__OSPF多选【62道题】

1.如图所示&#xff0c;路由器所有的接口开启OSPF&#xff0c;图中标识的IP地址为设备的LoopbackO接口的IP地址&#xff0c;R1、R2、R3的LoopbackO通告在区域1&#xff0c;R4的Loopback0通告在区域0&#xff0c;R5的LoopbackO通告在区域2&#xff0c;下列哪些IP地址之间可以相互…

Docker CIG使用

Docker CIG是什么 CIG为&#xff1a;CAdvisor监控收集、InfluxDB存储数据、Granfana图表展示 这个组合是一个常见的监控 Docker 容器的解决方案,它包括以下三个组件: cAdvisor (Container Advisor): cAdvisor 是一个开源的容器资源监控和性能分析工具。它能够收集有关正在运行的…

【Linux系统】进程间通信

本篇博客整理了进程间通信的方式管道、 system V IPC的原理&#xff0c;结合大量的系统调用接口&#xff0c;和代码示例&#xff0c;旨在让读者透过进程间通信去体会操作系统的设计思想和管理手段。 目录 一、进程间通信 二、管道 1.匿名管道 1.1-通信原理 1.2-系统调用 …