STL标准库与泛型编程(侯捷)笔记6(完结)

STL标准库与泛型编程(侯捷)

本文是学习笔记,仅供个人学习使用。如有侵权,请联系删除。

参考链接

Youbute: 侯捷-STL标准库与泛型编程

B站: 侯捷 - STL

Github:STL源码剖析中源码 https://github.com/SilverMaple/STLSourceCodeNote/tree/master

Github:课程ppt和源码 https://github.com/ZachL1/Bilibili-plus

文章目录

  • STL标准库与泛型编程(侯捷)
    • 40 一个万用的hash function
    • 41 Tuple 用例
    • 42 type traits
    • 43 type traits 实现
    • 44 cout
    • 45 movable元素对于不同容器速度效能的影响
    • 46 测试函数
    • 后记

下面是C++标准库体系结构与内核分析的第四讲笔记,也是这门课的最后一篇笔记。

主要包括tuple, type traits的介绍,移动构造等。

截至2024年1月9日,花费5天的时间,马不停蹄地结束《STL标准库与泛型编程》这门课。

40 一个万用的hash function

使用hashtable的容器的时候,可以设计一个hash function,下图是两种模式,一种是设计成成员函数,另一种是一般的函数。

在这里插入图片描述

具体怎么做,下图是几种方法。

左上角是naive approach:直接把属性的所有hash值加起来,这种方法在hashtable中会产生很多的碰撞,放在同一个bucket中的元素会多。

另一种做法是使用可变模板参数来做的hash_val()函数,产生种子,经过复杂的操作,得到hash值。

在这里插入图片描述

还有一种方法是利用struct hash的偏特化来实现hash function

在这里插入图片描述

在这里插入图片描述

41 Tuple 用例

std::tuple 是 C++ 标准库中的一个模板类,用于组织多个元素(值或者引用)为一个单一的对象。std::tuple 提供了一个元组(tuple)的概念,类似于一个固定大小的、不同类型的数组。

以下是一些关键的特性和用法:

  1. 组织多个元素: std::tuple 可以包含零个或多个元素,每个元素可以是不同类型的。

  2. 元素的访问: 可以使用 std::get 函数或结构化绑定(C++17 及以上)来访问元组中的元素。例如:

    #include <tuple>
    #include <iostream>int main() {// 创建一个包含整数、浮点数和字符串的元组std::tuple<int, float, std::string> myTuple(42, 3.14f, "Hello");// 使用 std::get 访问元组中的元素std::cout << "First element: " << std::get<0>(myTuple) << std::endl;std::cout << "Second element: " << std::get<1>(myTuple) << std::endl;std::cout << "Third element: " << std::get<2>(myTuple) << std::endl;return 0;
    }
    
  3. 结构化绑定(C++17 及以上): 可以使用结构化绑定直接将元组的元素绑定到变量,使得代码更加清晰:

    #include <tuple>
    #include <iostream>int main() {// 创建一个包含整数、浮点数和字符串的元组std::tuple<int, float, std::string> myTuple(42, 3.14f, "Hello");// 使用结构化绑定访问元组中的元素auto [first, second, third] = myTuple;std::cout << "First element: " << first << std::endl;std::cout << "Second element: " << second << std::endl;std::cout << "Third element: " << third << std::endl;return 0;
    }
    
  4. 元组的比较: std::tuple 支持比较操作,可以用于按照字典序比较元组。

  5. 元组的拆包: 可以使用 std::make_tuple 创建元组,也可以使用 std::tie 将元组的值绑定到变量,方便进行函数的多返回值:

    #include <tuple>
    #include <iostream>std::tuple<int, double, std::string> getValues() {return std::make_tuple(42, 3.14, "Hello");
    }int main() {int intValue;double doubleValue;std::string stringValue;// 使用 std::tie 拆包std::tie(intValue, doubleValue, stringValue) = getValues();std::cout << "Int value: " << intValue << std::endl;std::cout << "Double value: " << doubleValue << std::endl;std::cout << "String value: " << stringValue << std::endl;return 0;
    }
    

总体而言,std::tuple 提供了一种方便的方式来组织和处理多个元素,尤其在函数返回多个值的场景中使用较为方便。

在这里插入图片描述

tuple<Head, Tail…> 继承 tuple<Tail…>

这样的递归定义使得 tuple 类模板可以方便地处理可变数量的模板参数,每一层递归处理一个参数。这也是元编程中常见的技术,通过递归和继承来处理可变数量的参数。

在这里插入图片描述

42 type traits

在C++中,type_traits 是一种元编程技术,用于在编译时判断和查询类型的特性。它通常包含了一系列的嵌套类型成员(type members)或者常量值成员(value members),用于描述和查询类型的特性。这些特性包括是否有默认构造函数、是否是 POD(Plain Old Data)、是否具有特定的特性等等。

struct __true_type {
};struct __false_type {
};template <class _Tp>
struct __type_traits { typedef __true_type     this_dummy_member_must_be_first;/* Do not remove this member. It informs a compiler whichautomatically specializes __type_traits that this__type_traits template is special. It just makes sure thatthings work if an implementation is using a templatecalled __type_traits for something unrelated. *//* The following restrictions should be observed for the sake ofcompilers which automatically produce type specific specializations of this class:- You may reorder the members below if you wish- You may remove any of the members below if you wish- You must not rename members without making the correspondingname change in the compiler- Members you add will be treated like regular members unlessyou add the appropriate support in the compiler. */typedef __false_type    has_trivial_default_constructor;typedef __false_type    has_trivial_copy_constructor;typedef __false_type    has_trivial_assignment_operator;typedef __false_type    has_trivial_destructor;typedef __false_type    is_POD_type;
};// Provide some specializations.  This is harmless for compilers that
//  have built-in __types_traits support, and essential for compilers
//  that don't.#ifndef __STL_NO_BOOL__STL_TEMPLATE_NULL struct __type_traits<bool> {typedef __true_type    has_trivial_default_constructor;typedef __true_type    has_trivial_copy_constructor;typedef __true_type    has_trivial_assignment_operator;typedef __true_type    has_trivial_destructor;typedef __true_type    is_POD_type;
};#endif /* __STL_NO_BOOL */__STL_TEMPLATE_NULL struct __type_traits<char> {typedef __true_type    has_trivial_default_constructor;typedef __true_type    has_trivial_copy_constructor;typedef __true_type    has_trivial_assignment_operator;typedef __true_type    has_trivial_destructor;typedef __true_type    is_POD_type;
};__STL_TEMPLATE_NULL struct __type_traits<signed char> {typedef __true_type    has_trivial_default_constructor;typedef __true_type    has_trivial_copy_constructor;typedef __true_type    has_trivial_assignment_operator;typedef __true_type    has_trivial_destructor;typedef __true_type    is_POD_type;
};

type traits特化

在这里插入图片描述

type traits测试

string类里面没有虚析构函数:

在C++中,std::string 类的析构函数并不是虚析构函数。这是因为 std::string 类通常不被设计为作为基类使用,而是用作独立的、不涉及多态性的类。虚析构函数主要用于在继承关系中的基类,以确保正确调用派生类的析构函数。

由于 std::string 通常不作为基类使用,因此它的析构函数不需要是虚的。虚函数会引入额外的开销,包括虚函数表(vtable)的维护,而对于非多态的类来说,这是不必要的。

如果你需要在继承体系中使用多态性,可能会使用指向基类的指针或引用来操作派生类对象。在这种情况下,基类应该有虚析构函数,以确保正确调用派生类的析构函数。然而,对于 std::string 这样的类,通常不需要在继承体系中使用多态性,因此它的析构函数没有被声明为虚函数。

在这里插入图片描述

这里侯捷老师提到虚析构函数,这里复习一下:

虚析构函数(Virtual Destructor)是 C++ 中的一个概念,通常用于处理基类指针指向派生类对象时的正确析构行为。

当一个类中包含虚函数时,通常都应该声明一个虚析构函数。虚析构函数的声明形式如下:

class Base {
public:virtual ~Base() {// 虚析构函数的实现}// 其他成员函数和数据成员...
};

在上述代码中,~Base() 是虚析构函数。虚析构函数通过关键字 virtual 进行声明,这样派生类就可以选择性地覆盖它。这样一来,当使用基类指针指向派生类对象,并通过这个指针删除对象时,将会调用适当的派生类析构函数,确保对象的正确清理。

例如:

class Derived : public Base {
public:~Derived() override {// 派生类的析构函数实现}// 其他成员函数和数据成员...
};int main() {Base* ptr = new Derived();// 使用基类指针删除对象,调用的是派生类的析构函数delete ptr;return 0;
}

在这个例子中,通过基类指针 Base* ptr 删除一个 Derived 类型的对象时,由于基类析构函数是虚函数,将调用 Derived 类的析构函数。这样确保了在多态(polymorphic)情况下正确释放资源。

测试虚析构函数,type traits能否正确显示出来

在这里插入图片描述

下面用到了C++11的&&语法:

在C++11及之后的标准中,&& 是右值引用(Rvalue Reference)的语法。

右值引用是一种引用类型,用于表示对右值(如临时对象、将要销毁的对象等)的引用。在C++11中,引入了右值引用的概念,通过 && 来声明右值引用。右值引用的主要特点是能够绑定到临时对象,而传统的左值引用(&)主要用于绑定到可修改的左值。

以下是右值引用的基本语法:

T&& variable_name; // T 是某种类型,variable_name 是变量名

其中,T 是被引用的类型。右值引用主要用于优化资源管理和实现移动语义,其中移动语义可以避免不必要的内存拷贝,提高程序性能。

一个常见的例子是移动构造函数和移动赋值运算符的使用,它们使用右值引用来实现对资源的高效转移。例如:

class MyClass {
public:// 移动构造函数MyClass(MyClass&& other) {// 实现资源的移动}// 移动赋值运算符MyClass& operator=(MyClass&& other) {// 实现资源的移动return *this;}
};// 使用右值引用创建对象
MyClass obj1;
MyClass obj2 = std::move(obj1); // 使用 std::move 将左值转为右值

在上述例子中,std::move 函数用于将左值转为右值,这样可以调用移动构造函数或移动赋值运算符,从而实现高效的资源管理。Move constructor(移动构造函数)是C++11引入的一种构造函数,用于实现对象的资源转移,以提高程序的性能。它允许在不复制资源的情况下将对象的内容从一个对象转移到另一个对象。移动构造函数使用右值引用(Rvalue Reference)来实现。

在这里插入图片描述

43 type traits 实现

type traits实现 is_void

模板类的设计方法,有一个泛化版本,后面跟着特化版本。

下面的remove_const的特化,类型是_Tp const ,这是范围上的偏特化。

remove_volatile也是同样的操作。

remove_cv是调用remove_const和remove_volatile。

在这里插入图片描述

44 cout

cout 是 C++ 标准库中的输出流对象,用于将数据输出到标准输出设备,通常是控制台。它是 ostream 类的一个实例,是 C++ 中常用的输出工具之一。

一个东西想要能够丢给cout,就是对<<操作符的重载

在这里插入图片描述

下面就是各种类对<<操作符的重载,以实现在标准输出设备上输出。

在这里插入图片描述

45 movable元素对于不同容器速度效能的影响

测试三百万个元素放入不同的容器

movable元素对vector速度的影响

这里CCtor和MCtor都是构造函数的调用次数,由于vector的底层会两倍空间扩展,在扩展的时候会调用拷贝构造,所以这里调用次数为7194303,明显大于三百万。

在这里插入图片描述

movable元素对list速度的影响

在这里插入图片描述

movable元素对deque速度的影响

在这里插入图片描述

movable元素对multiset速度的影响

在这里插入图片描述

movable元素对unordered_multiset速度的影响

在这里插入图片描述

写一个moveable class

move constructor是用一个指针指向资源,避免资源的深度复制。

在这里插入图片描述

move assignment

在这里插入图片描述

46 测试函数

下图是对上面移动构造的时间开销的测试

在这里插入图片描述

vector的copy constructor

深拷贝:耗费大量时间

在这里插入图片描述

vector的move constructor

在这里插入图片描述

string时候movable呢?

如下图所示,string带有movable的功能,从&&右值可以看出。

在这里插入图片描述

后记

这是STL标准库与泛型编程的最后一篇笔记,这门课完结。

截至2024年1月9日,花费5天的时间,马不停蹄地结束《STL标准库与泛型编程》这门课。

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

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

相关文章

力扣(leetcode)第500题键盘行(Python)

500.键盘行 题目链接&#xff1a;500.键盘行 给你一个字符串数组 words &#xff0c;只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。 美式键盘 中&#xff1a; 第一行由字符 “qwertyuiop” 组成。 第二行由字符 “asdfghjkl” 组成。 第三行由字…

从比特币、以太坊生态,到AI与新公链复兴,谁将接棒2024年的主流叙事?

2023年10月份至今&#xff0c;现货比特币ETF一直都是促使市场反弹的核心叙事之一&#xff0c;如今靴子终于落地&#xff0c;那在ETF预期尘埃落定的大背景下&#xff0c;接下来的加密市场有哪些赛道值得关注&#xff1f; 泛比特币生态 2023年比特币生态浪潮中&#xff0c;OKX等赢…

企业信息化规划该如何落地?以制造型企业为例

企业信息化规划如何落地&#xff1f; 规划做好了&#xff0c;蓝图也画好了&#xff0c;人手一块大饼也已经揣好了&#xff0c;那么该怎么落地呢&#xff0c;这才是最关键的。 我将企业信息化规划落地分为4个周期&#xff0c;以最典型的制造行业为例&#xff0c;以简道云这个企…

Seata TM管理分支事务源码

TM相当于一个中间商&#xff0c;是没有涉及到任何数据库底层操作的。 TransactionalTemplate 1、TM向TC端发起一次开启全局事务的请求 io.seata.tm.api.TransactionalTemplate#beginTransaction --> io.seata.tm.api.DefaultGlobalTransaction#begin(int, java.lang.Strin…

配置DNS

vim /etc/named.conf vim /etc/named.rfc1912.zones cp named.localhost ./kgc.com.zone -p vim kgc.com.zone 设置备用dns服务器 修改主配置文件&#xff0c;并自动同步到从服务器

【分布式技术】监控平台zabbix介绍与部署

目录 一、为什么要做监控&#xff1f; 二、zabbix是什么&#xff1f; 三、zabbix有哪些组件&#xff1f; ​编辑Zabbix 6.0 功能组件&#xff1a; ●Zabbix Server ●数据库 ●Web 界面 ●Zabbix Agent ●Zabbix Proxy ●Java Gateway 四、zabbix的工作原理&#xf…

SQL-数据类型

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…

【python】进阶--->MySQL数据库(二)

一、sql语句(结构化查询语言) 要和数据库进行交互,需要使用到数据库认识的语言 : sql语句 是关系型数据库都需要遵循的规范。不同数据库都支持sql语句,但是都有特有内容。 二、sql语句分类 数据定义语言 : 用来定义数据库–数据库,表,列. 数据操作语言 : 对数据库表中的记录进…

Ubuntu12.0安装g++过程及其报错

Ubuntu12.0安装g过程及其报错 https://blog.csdn.net/weixin_51286763/article/details/120703953 https://blog.csdn.net/dingd1234/article/details/124029945

MATLAB | 龙年大吉,使用MATLAB绘制会动的中国风神龙

hey各位好久不见&#xff0c;龙年到了&#xff0c;这期画一期配色非常中国风的龙&#xff0c;这个造型的龙参考了某些html绘制龙的视频&#xff0c;但是由于html版全网都是也不咋给代码和代码出处&#xff0c;因此自己写了个MATLAB版本&#xff1a; 可以看到还是非常酷炫的&…

【LabVIEW FPGA入门】使用数字IO卡实现计数器输入功能

方法1&#xff1a; 1.首先需要用一个数字IO的输入FPGA端口&#xff0c;并将其拖入程序框图中&#xff0c;同时创建一个循环。 2.如果想要在循环中实现累加功能&#xff0c;就可以使用移位寄存器。 数字输入的当前值和历史值进行比较&#xff0c;用于一个判断大于&#xff0c;来…

【算法分析与设计】跳跃游戏

题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - …

阿里云高性能云服务器_云主机_云服务器详解

阿里云高性能云服务器60%单实例最大性能提升&#xff0c;35Gbps内网带宽&#xff0c;网络增强&通用型云服务器、本地SSD型云服务器、大数据型云服务器、GPU异构型云服务器&#xff0c;阿里云百科aliyunbaike.com分享阿里云高性能云服务器&#xff1a; 阿里云高性能云服务器…

基于STM32的温湿度传感器

一、创新实践实习内容 一:指导老师给我们介绍了广州粤嵌通信科技股份有限公司的企业文化与企业环境&#xff0c;简要地介绍了本行业的发展历史及未来发展趋势。讲解了Keil5的功能与应用。指导我们搭建STM32F407驱动环境以及学习相关芯片包的安装使用方法。并且带着我们对C语言…

力扣热题100

排序 快速排序 #include <iostream> #include <vector> using namespace std;// 快速排序函数&#xff0c;传入引用&#xff0c;以便修改原始数组 void quick_sort(vector<int>& q, int l, int r) {// 边界条件&#xff1a;如果左边界大于等于右边界&am…

基于SpringBoot+Vue实现的二手交易系统

系统介绍 校园二手交易网站是一种专门针对有二手物品交易需求用户的二手交易的网站。它的设计和开发主要是为了满足用户之间的二手物品交易需求&#xff0c;方便大家在线买卖二手物品。近年来&#xff0c;随着互联网技术的发展&#xff0c;人们越来越喜欢在线购物&#xff0c;…

NMEA0183协议相关笔记

协议基本知识 参考以前的文章 <北斗/GPS模块的使用-基于正点原子ATK-1218-BD>&#xff0c;文章链接&#xff0c;或者野火相关资料整理。 1、协议格式 2、地址段指令 1、标识 2、语句类型 二、指令内容 1、 GGA 2、GLL 3、GSA 4、GSV 5、RMC 6、VTG 7、ZDA 8、TXT

码牛课堂首推——鸿蒙南北双向开发学习路线图标准版~

鸿蒙&#xff01;鸿蒙&#xff01;鸿蒙&#xff01; 要说2023-2024年IT圈最火爆的名词&#xff0c;一定是鸿蒙&#xff01; 2023年9月25日&#xff0c;华为发布会正式宣布2024年第一季度将推出HarmonyOS NEXT版本&#xff0c;这意味着鸿蒙原生应用开发将彻底摆脱Android手机系…

Java实现在线编辑预览office文档

文章目录 1 在线编辑1.1 PageOffice简介1.2 前端项目1.2.1 配置1.2.2 页面部分 1.3 后端项目1.3.1 pom.xml1.3.2 添加配置1.3.3 controller 2 在线预览2.1 引言2.2 市面上现有的文件预览服务2.2.1 微软2.2.2 Google Drive查看器2.2.3 阿里云 IMM2.2.4 XDOC 文档预览2.2.5 Offic…

【simple-admin】FMS模块如何快速接入阿里云oss 腾讯云cos 服务 实现快速上传文件功能落地

让我们一起支持群主维护simple-admin 社群吧!!! 不能加入星球的朋友记得来点个Star!! https://github.com/suyuan32/simple-admin-core 一、前提准备 1、goctls版本 goctls官方git:https://github.com/suyuan32/goctls 确保 goctls是最新版本 v1.6.19 goctls -v goct…