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

news2024/9/23 11:24:29

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 which
                      automatically specializes __type_traits that this
                      __type_traits template is special. It just makes sure that
                      things work if an implementation is using a template
                      called __type_traits for something unrelated. */

   /* The following restrictions should be observed for the sake of
      compilers 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 corresponding
            name change in the compiler
          - Members you add will be treated like regular members unless
            you 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.coloradmin.cn/o/1369077.html

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

相关文章

diffusers加速文生图速度;stable-diffusion、PixArt-α

参考: https://pytorch.org/blog/accelerating-generative-ai-3/ https://colab.research.google.com/drive/1jZ5UZXk7tcpTfVwnX33dDuefNMcnW9ME?usp=sharing#scrollTo=jueYhY5YMe22 大概GPU资源8G-16G;另外模型资源下载慢可以在国内镜像:https://aifasthub.com/ 1、加速…

RK3568上如何使用MPP进行硬解码

目录 前言正文一、FFmpeg 拉流处理二、RK3568 mpp硬解码1、简介2、普通mpp解码流程3、核心代码 END、总结的知识与问题1、一直出现jitter buffer full 这样的问题2、如何打印帧率&#xff1f;3、分析av_packet_alloc、av_init_packet、av_packet_unref、av_packet_free、av_fra…

尤雨溪:框架挖坑靠文档来补,这算 PUA 用户吗?丨 RTE 开发者日报 Vol.122

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

经典八股文之RocketMQ

核心概念 NameServer nameserver是整个rocketmq的大脑&#xff0c;是rocketmq的注册中心。broker在启动时向所有nameserver注册。生产者在发送消息之前先从 NameServer 获取 Broker 服务器地址列表(消费者一 样)&#xff0c;然后根据负载均衡算法从列表中选择一台服务器进行消…

ADKEY多按键制作阻值选择2(回答网友问题)

回答网友的问题 网友原来的电路图 adc组合按键电阻阻值参考_ad 检测四个开关 阻值-CSDN博客https://blog.csdn.net/weixin_43833645/article/details/128615455?spm1001.2014.3001.5501截图如下 现在对齐进行简化&#xff08;少了一个按键&#xff09; 其采样值列表如下图 …

Web3.0与虚拟现实:改变前端开发的新机遇

Hello大家好&#xff01;我是咕噜的铁蛋&#xff01;。近年来&#xff0c;Web3.0和虚拟现实技术的兴起引起了广泛的关注和讨论。它们不仅在互联网领域带来了革命性的变化&#xff0c;同时也给前端开发者带来了全新的机遇和挑战。今天铁蛋讲和大家一起探讨Web3.0与虚拟现实如何改…

游戏、设计选什么内存条?光威龙武系列DDR5量大管饱

如果你是一位PC玩家或者创作者&#xff0c;日常工作娱乐中&#xff0c;确实少不了大容量高频内存的支持&#xff0c;这样可以获得更高的工作效率&#xff0c;光威龙武系列DDR5内存条无疑是理想之选。它可以为计算机提供强劲的性能表现和稳定的运行体验&#xff0c;让我们畅玩游…

Python猜数游戏

文章目录 1 Game Rule2 Code3 Result 1 Game Rule 猜数字游戏目的是猜测出程序想出的数字&#xff0c;基本逻辑&#xff1a; 程序随机选择1到100之间的一个数字或任何其他数字组合&#xff1b; 然后它会要求玩家输入它的建议&#xff1b; 然后它会检查这个数字是否与计算机随…

React 入门 - 05(响应式与事件绑定)

本章内容 目录 一、响应式设计思想二、React 中的事件绑定 继上一节我们简单实现一个 TodoList来更加了解编写组件的一些细节。本节继续这个案例功能的完成。 一、响应式设计思想 1、在原生的 JS中&#xff0c;如果要实现点击”提交“按钮就将输入框的内容添加至页面列表中&…

mysql忘记root密码后怎么重置

mysql忘记root密码后重置方法【windows版本】 重置密码步骤停掉mysql服务跳过密码进入数据库在user表中重置密码使用新密码登录mysql到此&#xff0c;密码就成功修改了&#xff0c;完结&#xff0c;撒花~ 重置密码步骤 当我们忘记mysql的密码时&#xff0c;连接mysql会报这样的…

虾皮商品标题:如何创建有效的虾皮商品标题

虾皮&#xff08;Shopee&#xff09;平台是一个非常受欢迎的电商平台&#xff0c;为卖家提供了一个广阔的销售渠道。在虾皮上&#xff0c;一个有效的商品标题是吸引潜在买家注意力的关键元素之一。一个好的商品标题能够吸引更多的点击和浏览量&#xff0c;从而提高销售机会。下…

vue设置height:100vh导致页面超出屏幕可以上下滑动

刚开始设置的height:100vh&#xff0c;就会出现如图的效果&#xff0c;会出现上下滚动 <template><view class"container">......</view> </template><style lang"scss">.container {height: 100vh;} </style> 解决方…

99%的人还不知道的私域流量管理工具

一、多个微信可以聚合管理 简单来讲这是一款一个窗口对多个个人微信号的聊天转化工具&#xff0c;一款集成众多功能的网页版聊天工具&#xff0c;支持多开N个微信号在同一个窗口&#xff0c;实现了集中会话&#xff0c;不用来回切换账号。 二、常用语快捷回复 可对常用的问题…

代码随想录算法训练营Day08|344.反转字符串、541. 反转字符串II、卡码网:替换数字、151.翻转字符串里的单词、卡码网:右旋字符串

文章目录 一、344.反转字符串1. 双指针法 二、541. 反转字符串II1. 字符串解法 三、卡码网&#xff1a;替换数字四、151.翻转字符串里的单词1.使用库函数2.自行编写函数3.创建字符数组填充3.双反转移位 五、卡码网&#xff1a;右旋字符串1. 自行编写函数 总结 一、344.反转字符…

专利:发明和实用新型的区别

上一篇给大家分享了专利&#xff0c;今天说一下发明和实用新型得区别。 什么是发明专利&#xff1f; 发明&#xff0c;是指对产品、方法或者其改进所提出的新的技术方案。发明与实用新型和外观设计一起&#xff0c;构成我国专利法所保护的对象。发明专利作为知识产权的一种&am…

面向设计师的11个必备AI工具

在当今快速发展的设计领域&#xff0c;人工智能&#xff08;AI&#xff09;工具已成为不可或缺的创新催化剂。这些工具专门用于提高效率和创造力&#xff0c;从而重新定义传统的设计方法。AI正在彻底改变设计师的工作方式&#xff0c;从自动处理任务到发掘新的创造力机会&#…

【微信支付】【java】Springboot对接开发微信支付

本文章是介绍java对接微信支付&#xff0c;包括微信预下单、支付、退款等等。 一、微信配置申请 1、微信支付配置申请 详细操作流程参考官方文档&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml#part-1 配置完成需要以下信息&#xff1…

银河麒麟Kylin-Server-V10-SP3使用ISO镜像搭建本地内网YUM/DNF源cdrom/http

机房服务器安装一般是内网环境&#xff0c;需要配置本地的YUM/DNF源。本文介绍通过ISO镜像搭建内网环境的UM/DNF源 准备工作&#xff1a; 提前准备好Kylin-Server-V10-SP3的ISO镜像文件。 本机IP地址&#xff1a;192.168.40.201 镜像存放目录/data/iso/Kylin-Server-V10-SP3-Ge…

以unity技术开发视角对android权限的讲解

目录 前言 Android权限分类 普通权限 普通权限定义 普通权限有哪些 危险权限 危险权限的定义 危险权限有哪些 动态申请权限实例 申请单个权限实例 第一步&#xff1a;在清单文件中声明权限 第二步&#xff1a;在代码中进行动态申请权限 申请多个权限实例 第一步&am…

[C#]使用PaddleInference图片旋转四种角度检测

官方框架地址】 https://github.com/PaddlePaddle/PaddleDetection.git 【算法介绍】 PaddleDetection 是一个基于 PaddlePaddle&#xff08;飞桨&#xff09;深度学习框架的开源目标检测工具库。它提供了一系列先进的目标检测算法&#xff0c;包括但不限于 Faster R-CNN, Ma…