
C++
文章平均质量分 82
C++学习
栖林_
一个励志于做全栈工程师的平平无奇大学生,希望在这里留下自己学习的记录
展开
-
并发编程之ABA问题
ABA问题是并发编程中一个经典的问题,尤其在使用无锁数据结构时容易发生。它源于变量值经历了"A→B→A"的变化序列,导致程序逻辑误判状态未改变。以下是详细解析:当某个线程执行**CAS(Compare-and-Swap)**操作时:此时程序逻辑可能因中间状态变化而出现错误。假设一个无锁链表结构:线程1操作:线程2操作:结果:线程1执行时,发现仍是0x1000,误以为链表未变化,实际上:原创 2025-02-17 15:45:36 · 747 阅读 · 0 评论 -
深入理解无锁队列与C++原子操作
原子操作是不可分割的最小操作单元,要么完全执行,要么完全不执行。C++11通过<atomic>原创 2025-02-17 15:44:31 · 383 阅读 · 0 评论 -
C++多态:静态多态vs动态多态
多态(Polymorphism)作为面向对象编程的三大核心特性之一,是构建灵活、可扩展软件系统的关键所在。在C++中,多态的实现主要分为静态多态(Static Polymorphism)和动态多态(Dynamic Polymorphism)两种形式,它们以不同的方式实现了"一个接口,多种实现"的核心思想。在这一篇博客里我有详细介绍(原创 2025-02-12 17:49:57 · 843 阅读 · 0 评论 -
从HTTP1.0到HTTP3.0性能革命
简单介绍HTTP1.0到HTTP3.0的特点和发展原创 2025-02-12 17:47:35 · 773 阅读 · 0 评论 -
C++ CRTP:奇异递归模板模式的原理与应用
CRTP 的英文全称为,顾名思义,就是让一个类在继承时将自身作为模板参数传给其基类。// 基类模板public:// 调用派生类的成员函数 implementation()// 基类模板 template < typename Derived > class Base {public :// 调用派生类的成员函数 implementation() void interface() {} // 如果派生类没有重写,基类可以提供一个默认实现 void implementation() {原创 2025-02-07 11:03:29 · 1147 阅读 · 0 评论 -
git的理解与使用
一般来说master分支是最稳定的,也就是服务部署的分支,然后是dev开发分支,开发分支可以再继续细分到具体的某个人,如果开发只有你一个人来包揽也是可以的,类似的还有feature分支。master分支或者main分支为主分支,一般大型项目都不在主分支上,分支就像是分身一样,写不同部分的代码,最后合并就是完整的项目,因此我们也可以进行分支的创建、切换、合并。当我们使用add之后,代码就会被存储在暂存区,只有commit之后,也就是提交代码,整个代码才会被放入版本库,也就是上图的master文件夹中。原创 2025-01-24 17:16:47 · 1497 阅读 · 0 评论 -
WebSocket协议介绍与C++实现
WebSocket协议建立在HTTP协议之上,首先通过一个HTTP请求来进行握手。一旦握手完成,客户端和服务器之间的连接会被“升级”到WebSocket协议,之后通信不再依赖HTTP,而是直接使用WebSocket协议。原创 2024-11-13 21:32:10 · 1260 阅读 · 0 评论 -
C++20协程详解
全网最详细协程讲解原创 2024-11-12 23:01:54 · 1207 阅读 · 0 评论 -
八大技术架构与演进2
比如,在一个电商系统中,可以将用户数据、订单数据、商品数据分别存储在不同的数据库中,以减少单库的负载。但是这种做法其实是增加了数据库的运维难度,这种其实也就叫做分布式数据库,逻辑上是一整个大的数据库,但是实际上却是由各个分开的数据库来组合实现的功能。在同一台服务器中,可以由很多个不同的镜像运行,他们之间是独立的,我们甚至可以粗暴的任务,一个docker容器就是一个简单的操作系统。我们可以将不同的业务分给不同的开发团队去维护,每个团队独立实现自己的微服务,互相之间的数据进行隔离。原创 2024-11-12 20:52:26 · 374 阅读 · 0 评论 -
Linux文件描述符详解及其应用
系统会为进程分配一张文件描述符表(FD Table),其中每个打开的文件或资源都会占用一个文件描述符,进程通过文件描述符来读写、控制和管理这些资源。在编程中,可以通过重定向这些文件描述符来改变数据的输入和输出位置,例如将标准输出重定向到文件,或从文件而不是键盘读取输入。每当打开一个文件时,系统会返回一个文件描述符,后续对文件的所有操作(如读取、写入、关闭)都依赖这个文件描述符。每个进程在打开文件、套接字等资源时,操作系统会分配一个可用的文件描述符。文件描述符使文件的操作变得简单,能统一处理不同的资源。原创 2024-10-26 14:08:49 · 1667 阅读 · 0 评论 -
Linux下的线程同步与死锁避免
即,线程只有在能够获取所有资源时才会继续执行,否则会释放已经持有的资源,避免持有并等待的发生。为了避免这种情况,我们可以在申请资源之前,确保线程不占有其他资源,或者一次性申请所有所需资源。在某些情况下,我们可以通过将资源转换为可共享的资源来破坏互斥条件,从而避免死锁。是指存在一个线程循环等待链,每个线程都在等待下一个线程持有的资源。通过一次性申请资源,线程要么成功获取所有资源并继续执行,要么立即释放资源,减少持有并等待的风险。通过这种方式,线程不会无限期地等待资源,从而避免了死锁的发生。原创 2024-10-26 14:07:51 · 1209 阅读 · 0 评论 -
Linux环境C++多线程调试工具和内存泄漏工具介绍
幸运的是,Linux 提供了多种调试工具来帮助我们排查多线程相关的问题和内存泄漏。AddressSanitizer 是 GCC 和 Clang 编译器中的另一个强大的工具,用于检测内存错误,包括越界访问、堆栈溢出和内存泄漏。除了多线程问题,内存管理也是 C++ 程序中常见的挑战之一。执行该命令后,Valgrind 会跟踪程序的所有内存分配和释放情况,并在程序结束时给出详细的报告,指出泄漏的内存位置和大小。是一个用于跟踪程序执行时系统调用的工具,对于多线程程序,它可以帮助开发者检查线程相关的系统调用(例如。原创 2024-10-26 14:07:03 · 1166 阅读 · 0 评论 -
C++11中的同步互斥机制详解
std::mutex是 C++11 提供的最基本的互斥锁,用于保护共享资源,确保同一时刻只有一个线程能够访问该资源。它提供了lock()和unlock()两个基本方法,分别用于加锁和解锁。std::mutex是 C++11 提供的 RAII(资源获取即初始化)机制的封装类,用于自动管理mutex的生命周期。构造时加锁,析构时解锁,确保在函数作用域结束时自动释放锁,避免了手动管理锁的复杂性。是一个比更加灵活的锁管理类。与不同,延迟锁定:可以在对象创建时不锁定,而在需要时调用lock()。原创 2024-10-26 14:06:21 · 882 阅读 · 0 评论 -
C++中RAII详解
在这些场景中,RAII 的思想同样适用,即在构造时获取资源,在析构时释放资源。智能指针是 C++ 标准库中的一种 RAII 实现,它通过封装原始指针的分配与释放逻辑,帮助开发者自动管理内存。RAII 将资源管理的职责交给对象的构造函数和析构函数,使得开发者无需手动编写资源释放代码,大幅减少代码量和潜在的错误。使用 RAII 管理锁的生命周期,在函数结束或异常时自动释放锁,从而避免死锁或忘记解锁的问题。智能指针的使用减少了手动管理内存的复杂性,并且在异常情况下也能自动释放内存,避免了内存泄漏。原创 2024-10-26 14:05:18 · 1163 阅读 · 0 评论 -
Linux中exec系列函数与fork函数
函数是进程管理中的两个重要组成部分。它们在创建和执行进程时扮演着关键角色,理解它们的工作原理及相互关系对于系统编程至关重要。后,当前进程(父进程)会被复制一份,生成一个新的进程(子进程)。一起使用,以便创建新的进程并在其中执行新程序。系列函数用于在当前进程的上下文中执行新的程序。在 Linux 和其他 Unix-like 操作系统中,后,当前进程的代码和数据将被新程序替换。是用于创建新进程的系统调用。原创 2024-10-21 12:33:23 · 722 阅读 · 0 评论 -
C++智能指针对比与总结
C++的智能指针是RAII的一种应用 自动管理动态内存的工具 可以避免显示的内存释放 减少内存泄漏和为定义行为的可能性 C++标准库提供了三种主要的智能指针 unique_ptr shared_ptr weak_ptr。这个智能指针是共享对象的所有权的 是使用引用计数来维护同一个对象 当最后一个shared_ptr被销毁时 对象才会被释放。这是一种弱引用 主要是和shared_ptr配合使用的 他不影响对象的引用计数 也就说他并不会独立拥有对象本身。原创 2024-10-21 12:30:03 · 251 阅读 · 0 评论 -
C++服务端的配置文件库介绍
Boost.PropertyTree 是 Boost 库的一部分,用于处理层次结构的属性数据,如 XML、JSON 和 INI 文件。jsoncpp 是一个用于解析和生成 JSON 格式数据的库。JSON 格式通常用于现代应用程序的配置文件,因其可读性强且易于使用。在 C++ 项目中,灵活地读取用户配置是提升软件可用性的重要部分。本文将介绍几种常见的 C++ 配置库,包括它们的原理和使用方法。它通过逐行解析文本文件,识别键值对和节(section),便于简单的配置管理。原创 2024-10-19 11:22:39 · 963 阅读 · 0 评论 -
C++STL库全详解
因此他的迭代器需要维护的信息也很多 但是我们要知道这其中的数据单元是什么 其实还是元素本体 需要有 指向当前元素的指针(找到元素的基本单位) 指向整个指针数组的指针(用来找具体在哪一个缓冲区的指针)指向具体缓冲区的指针(表示当前元素所在的缓冲区)对于对象的构造和析构在空间的申请和释放是分开的 有些对象的构造不需要构造函数 有些对象析构不需要析构函数 将这两个过程分开就能提高程序的性能了 前提是我们需要通过类型萃取来获取类型是否调用 可以通过迭代器来获取 这部分也是比较复杂的。原创 2024-10-18 18:57:07 · 1494 阅读 · 0 评论 -
常见开源组件的详解
代理函数(stub):是负责客户端和服务器之间的通信 主要是为远程服务调用提供的一个本地接口 把远程调用的过程隐藏起来 他的内部处理功能就是序列化与反序列化 错误处理 返回结果 这种代理函数也支持多种编程语言 让不同语言的服务也能够通信。它遵循“Django 管理后台”的理念,提供了一个完备的后台管理界面,开发者可以快速上手并生成高效的 Web 应用。学过HTTP协议的错误处理都知道 这个玩意的错误机制是不太好的 客户端要根据状态码的不同处理不同的错误情况。原创 2024-10-13 20:03:13 · 993 阅读 · 0 评论 -
C++多态常见问题
重写指的是在继承关系中子类重新定义继承来的虚函数 重写的函数名\参数列表\返回值类型必须和父类一致 被继承的函数必须是虚函数 可以指定父类显示调用基类的被重写函数 属于动态多态 通过重写子类中的虚函数表实现。重载指的是在同一个作用域中 函数名相同 但参数列表不同 包括类型\个数\顺序 的函数 返回值不同不算重载 属于静态多态 底层原理是在编译时形成不同的函数名 链接时区分链接。重定义指的是在继承关系中 子类重新定义继承来的非虚函数 父类的函数被隐藏 可以使用域作用限定符来访问父类中的同名函数。原创 2024-10-08 16:53:16 · 299 阅读 · 0 评论 -
C++重载(Overloading)、重写(Overriding)、重定义(Hiding)的对比与区别
重定义指的是派生类中的函数与基类中的同名函数没有完全相同的签名(例如参数列表不同),但基类中的函数并不是虚函数。在这种情况下,派生类中的函数隐藏了基类中的同名函数,即使通过基类指针也无法访问被隐藏的基类函数。函数名相同,但基类的函数不是虚函数。可以参数列表不同,但即便相同,仍会隐藏基类的函数。基类函数被隐藏后,使用基类指针调用时只会访问派生类的版本。重定义可能会导致意外的行为,因此需要注意。public:public:在这个例子中,Child类中的print()函数隐藏了。原创 2024-10-08 10:16:49 · 1465 阅读 · 0 评论 -
C++继承与组合详解与对比
继承是一种用于创建新类的机制,允许新类(子类)从已有类(基类)继承属性和方法。继承形成了类与类之间的“是一个”关系(is-a relationship)。public:class Dog : public Animal { // Dog 继承自 Animalpublic:在上述代码中,Dog类继承自Animal类,Dog类可以访问Animal类的方法。组合是一种通过将对象嵌套到另一个对象中的方式来实现代码复用。它形成了“有一个”关系(has-a relationship)。原创 2024-10-04 12:32:29 · 664 阅读 · 0 评论 -
C++异步操作实现线程池
他的一个重要的特性就是能够阻塞当前的线程,一直到异步操作完成,从而确保在获取结果的时候,异步工作线程的任务是完成的。当我们在进行多线程中使用异步任务时,std::future是用来帮我们在需要的时候获取任务执行的结果。这是将一个函数封装起来,也可以返回一个封装对象,来获取他保存的这个函数的执行结果。其实就是设置,在获取结果时,才会进行传参调用,deferred本身是推迟的意思。,是如果有结果的话,直接获取结果,没有的话也是会阻塞等待。在我们调用获取结果之后,才显示正在计算,执行异步任务,原创 2024-10-03 11:26:35 · 951 阅读 · 0 评论 -
C++引用指针大对比
特性引用指针是否需要初始化必须在声明时初始化可以声明后再初始化是否能为空不能可以为空 (nullptr是否可重新绑定不能,绑定后不能更改可以重新指向不同的对象访问方式直接使用需要使用解引用是否可指向不同对象否是内存占用不占用额外内存占用内存,存储对象地址能否指向数组不能用于遍历数组可以用于数组遍历。原创 2024-10-03 09:52:55 · 1010 阅读 · 0 评论 -
C++常引用详解
是C++中的一种引用类型,它允许你通过引用访问某个变量,但不允许通过该引用修改变量的值。(rvalue)是一个临时值,通常不能通过变量的名字访问,它仅存在于表达式的计算过程中。是一个右值(临时对象),如果没有常引用,临时对象会在语句结束后销毁。:常引用的一个重要特性是它可以绑定到临时对象(右值),并延长该临时对象的生命周期。简单来说,右值就是临时、短暂的值,通常用于表达式的中间结果或临时对象,不具有持久性。当一个函数返回一个较大的对象时,可以通过常引用返回,避免返回值的拷贝。原创 2024-10-03 09:45:49 · 963 阅读 · 0 评论 -
C++类型强转详解const_cast,reinterpret_cast,static_cast与dynamic_cast
需要注意的是,这种类型转换是在编译时进行转换,并且不会进行运行时类型检查(RTTI),因此他从子类转父类是安全的,从父类向子类是不安全的,不安全就类似于强制转换。是最不安全的类型转换操作符,通常用于在不相关类型之间进行转换,或者将指针和整数类型之间进行转换。这种方式虽然简单,但缺乏明确性(可读性也一般般)和安全性,编译器不会检查转换的有效性。在 C++ 中,类型转换是一个常见的需求。)之外,C++ 提供了更安全、可读性更强的类型转换操作符,包括。本文将详细介绍这些操作符的用法,并对比它们之间的区别。原创 2024-10-02 17:47:30 · 978 阅读 · 0 评论 -
GTest测试框架介绍
GTest是谷歌发布的一个跨平台的单元测试框架,主要是为了在不同平台上编写的C++单元测试而生成的。测试中可以有多个测试套件,可以包含一组单元测试,不是很好理解,可以认为这是一个测试环境。测试程序中可以有很多测试套件,对应着全局,每一个测试套件中可以有多个单元测试。这其实就是我们用户自己定义的一个测试环境,是一个全局的测试环境类。如果局部需要设置全局的环境,就需要使用之前的全局的继承。在用例测试中,每一次单元测试都是单独进行的,互不影响。提供了丰富的断言,致命和非致命的判断,参数化。原创 2024-10-01 16:28:39 · 1061 阅读 · 0 评论 -
SQLite数据库介绍
SQLite是一个本地化的数据库,不需要客户端服务端什么的配置,主打就是轻量化方便化。他也不是一个独立的进程,而是可以根据应用程序的需求,可以进行静态或者动态的连接。第三个参数是flag是可以设置文件的打开方式,提供下面的宏可以选择。需要注意的是 在SQLite中一个数据库对应了一个数据库文件。而且他是直接存储在磁盘文件的,提供了简单易用的API接口。第一个参数是文件名,第二个参数是传入一个句柄指针的地址。如果是其他值的话就代表着有问题,需要查找对应的宏来看到。这是一个执行语句的操作函数。原创 2024-09-30 19:32:06 · 911 阅读 · 0 评论 -
C/C++static关键字详解
static的意思是静态的一开始在学习C语言时,我们时用它来控制变量和函数的作用域,也就是使用范围,后面学习到进程地址空间,才了解到他也改变了存储的区域我们知道进程地址空间可以大致分为栈区、堆区、静态区诶这个静态区是不是眼熟,没错static修饰的变量都存在静态区,一直到程序结束时才会释放额外bb一句,所有的常量也存在静态区简单说,static修饰的对象无非就是变量和函数,但是变量和函数放的位置不一样,static的作用也不一样C语言中static一共有三个用法这里对函数和全局变量的限制是相同的,目前还没有原创 2024-09-30 12:04:20 · 893 阅读 · 0 评论 -
Linux多线程——互斥锁的封装与生产消费模型的实现
为了更方便的使用互斥锁,我们把系统提供的互斥锁接口进行封装,并且贯彻一下RAII思想,让我们的使用更加方便。生产者与消费者之间的关系,不允许一边写一边取,这是互斥关系,并且要求先写后取,这是互斥关系。我们这样定义,生产者负责布置任务,然后通过阻塞队列,传递给消费者,让消费者完成任务。生产者与生产者之间的关系,我们不允许两个生产者共同写,他们之间是互斥关系。消费者与消费者的关系,我们也不允许两个消费者共同取,他们之间也是互斥关系。这里的产品可以是很多东西,我们可以认为产品是一个类,这个类可以是一切。原创 2024-09-06 19:51:43 · 333 阅读 · 0 评论 -
Linux多线程——利用C++模板对pthread线程库封装
因为这个类创建之后并没有真正创建线程,没有分配线程id,而Start作为主线程需要完成的任务就是创建新线程,更改线程的运行状态,返回线程创建成功与否。这样一来,作为静态成员函数是无法直接使用类内成员的,也就是无法使用这个回调函数,因此将this指针作为参数传递进去是一个很好的选择。我们使用C++的模板对其封装可以让他的使用更加方便,并且经过测试可以让我们更加直观的了解到线程互斥和同步的重要性。如果我们直观理解的话,其实就是在判断的时候,在五个线程都只剩下了1张票时,几乎同时进了这个判断。原创 2024-09-03 21:48:27 · 843 阅读 · 0 评论 -
C++单例模式与特殊类的设计
第一种思路就是,禁止直接使用构造函数,只能通过我给你的静态成员函数接口调用,而且必须设置为静态的,如果是非静态成员函数,就首先需要实例化一个对象才能调用,于是就循环调用了。而设计模式就像是武功里的外功,属于是学会了,但是要怎么样才能把这个功力的作用最大化,在哪些条件下用什么样的内功能破解,研究的是这个问题。例如,我想设计一个只能在栈或堆上实例化的类应该怎么做,我想设计一个不能被拷贝或继承的类应该怎么做,这些就是外功,是有固定章法的。在类里面的静态实例主要起声明的作用,初始化静态实例需要在类外做。原创 2024-08-31 18:55:33 · 1157 阅读 · 0 评论 -
C++智能指针详解
简单说其实,weak_ptr是可以从一个shared_ptr或者weak_ptr对象构造出来的,而他只有获得资源的观测权,并没有实际的共享资源,因此也没有增加引用计数,使用weak_ptr的use_count()成员还可以观测到资源的引用计数。这样做的本质其实是将这个资源托管给了对象,我们之前学类和对象的时候,他是可以自动调用构造和析构函数的,这就意味着我们不需要显示释放资源,并且可以让资源在其生命周期内始终有效,因为在调用析构的时候,才会释放资源。原创 2024-05-28 20:32:04 · 853 阅读 · 0 评论 -
C++异常处理机制
异常是是C++处理程序错误的一种方式,当程序发生错误的时候,就会抛出异常,这个异常可以是程序自发给出的,也有可能是我们手动写的throw,当抛出异常之后,我们可以在别的地方捕获异常,catch到就可以对异常进行提示和处理。需要注意的是,当抛出异常时,也就是执行到throw语句的时候,会直接跳出到catch的语句,throw后面的语句就不会被执行,如果抛出的异常没有被捕获,那么程序就会终止,显示未经处理的异常。catch:这个是捕获异常,当捕获到了这个异常(类)的时候,需要执行的语句。原创 2024-05-20 14:48:50 · 627 阅读 · 0 评论 -
C++11特性(三)
上面的参数args前面有省略号,表示一个可变参数模板,带省略号的参数我们称之为参数包,里面包含了有限多个参数,我们无法直接从参数包args中获取每个参数,只能通过递归的方式来打开这个包,一步步获取。但是有人要说了,那万一我要用全局的变量呢,之前我们讲过,一对大括号其实就是一个小环境,那么这个小环境里面是不能随便用外面的变量的,因为函数和类本身的设计还是需要高内聚低耦合的。在原先的模板中,我们只能接受一定数量的模板参数,在可变参数模板这里比较抽象,使用也有一定技巧,需要在实践中才能真正理解。原创 2024-05-16 20:53:54 · 1088 阅读 · 0 评论 -
C++11特性(二)
这里的临时对象其实就很多余,这时我们可以写一个右值引用的拷贝构造,因为编译器会调用最合适的那个,他就会调用这个我们写的交换的逻辑,而不是那个逐一拷贝的深拷贝了。左值表示的是一个数据的表达式,比如说变量的名字,或者是解引用的指针,我们可以获取左值的地址,并且可以对左值赋值,左值可以出现在赋值符号的左边,而右值不行。右值的本质上也是数据的表达式,但是与左值有不同,例如字面常量,表达式的返回值,函数的返回值(非左值引用返回),右值可以出现在赋值符号的右边,不能取地址。这些用法是我们可以容易理解的。原创 2024-05-14 20:47:16 · 320 阅读 · 0 评论 -
C++11特性(一)
C++11可以说是C语言演变成C++之后第二个重大的标准了,上一个重大的标准是C++98C++11相较于C++98带来了数量非常非常多的变化,新特性,对C++03进行了很多修正,甚至让C++11变得很不“C++”但是C++11能更好的用于系统开发和库开发,语法也更进一步泛化,简单化,稳定,安全这里介绍一些比较实用的语法特性。原创 2024-05-12 23:44:19 · 616 阅读 · 0 评论 -
哈希应用之布隆过滤器及其实现
这也就是为什么我们称之为过滤器,简单说一种应用就是用户注册时不允许重复名称,当我们查询时,发现不存在,这时就不需要再额外消耗资源去数据库中进行对比了,直接就可以确认,而当布隆过滤器发现,他是有可能存在的时候,再到数据库中对比,如果真的存在,再说不允许重复名称即可,这样就能节省大量的服务器资源,还能提高查询效率。但是这种存在依旧是“不可靠”的,在数据量特别巨大的时候,可能是别的字符串,恰好占用了这两个地址,此时就会误判,但是判断不存在的时候就是可靠的了,因为只要有一个是0,就说明这个字符串并不存在。原创 2024-05-02 18:07:45 · 502 阅读 · 0 评论 -
哈希应用之位图及其实现
第二种思路是使用两个普通位图,第一个位图来表示第一位,第二个位图来表示第二位,这样每次判断的时候虽然要将两个位图结合起来用,但是好在有我们刚刚实现的,也可以直接用库里面的。一个位置是x的位置想要置1的话,就说明不管原来是什么,置1之后结果一定是一,符合这个条件的位运算就是给这一位按位或1,那么同理的,后面分别就是按位与0,按位与1。假设是x,那么x/32,就是对应的第几个int,这里对应的是下标,就是从0开始的,x%32对应的是int的第几个位置了。排序加二分是NlogN的,哈希的话会好很多,是常数级的。原创 2024-04-30 18:38:20 · 355 阅读 · 0 评论 -
哈希封装unordered系列关联式容器
这里实现++主要有一个难点,就是当一个哈希桶走完的时候,我们如何找到下一个有效的哈希桶,一种思路是当场直接计算,取到下一个表中的值,计算出对应的哈希地址,第二种是直接现场推演,只要没有走出整个表,当我们找到一个不为空的节点时,这就是++的下一个位置,如果一直走出了表,就说明到了结尾,赋值为空即可。我们知道了这个错误的产生原因,就有思路可以解决了,就是不让他自动构造,我们手动构造一个迭代器给她返回就没问题了,也就是使用auto接收插入的返回值,然后再手动构造一个const迭代器,返回,就解决了这里的报错。原创 2024-04-24 23:10:42 · 577 阅读 · 0 评论