自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(36)
  • 收藏
  • 关注

原创 快速排序

当q[l]作分界点时,递归时使用j,当q[r]作分界点时,递归使用i,避免边界问题。最好 O(nlogn),最坏O((n^2)

2025-06-04 23:12:02 59

原创 一篇学习CSS的笔记

Cascading Style Sheets简称CSS,中文翻译为层叠样式表。当HTML被发明出来初期,不同的浏览器提供了各种各样的样式语言给用户控制网页的效果,HTML包含的显示属性并不是很多。但是随着各种使用者对HTML的需求,HTML添加了大量显示功能,以至于变得十分臃肿。随后CSS便诞生了。CSS是一种用来表现HTML等文件样式的计算机语言。仅有HTML的网页显示效果往往简陋不堪到难以入目。

2025-05-28 17:00:33 1259

原创 一篇笔记总结HTML基础知识

它们都是标签的属性,很多标签都需要借助标签的属性来设置标签对应的展示效果。form标签的action属性的属性值为后台服务器的地址,这样用户使用了提交按钮后就可以真的把用户的信息传递到后端服务器,使用了重置按钮后输入的信息才会真的重置。除了基本的表格标签外,如果想要在表格中设置表格大标题和表头单元格(表格的第一行内容),可以使用caption(双)和th(双)标签来设置。从表格中可以看到两种不同的标签对应的作用却是相同的。因此,标签的学习可以分为四个部分:排版标签、文本格式化标签、媒体标签、链接标签。

2024-07-28 20:59:34 2692 33

原创 原子操作std::atomic

std::atomic是 C++11 标准库提供的一个模板类,用于实现原子操作。原子操作是指不会被线程调度机制打断的操作,即这种操作一旦开始,就一直运行到结束,中间不会有任何线程切换。在多线程编程中,原子操作对于确保数据的一致性和避免数据竞争至关重要。实际上,使用编译器编译的简单语句,即使仅为简单的输入输出,也是分步执行的,都不是原子操作。因此针对同一对象的访问就有可能产生不可预料的问题。在单线程的程序中,标准库提供的操作通常已经解决了这些问题。

2024-05-13 23:58:51 896 89

原创 future wait_for()成员、shared_future

wait_for():等待其异步操作操作完成或者超出等待,用于检查异步操作的状态。wait_for()可以接受一个std::chrono::duration类型的参数,它表示等待的最大时间,会返回一个std::future_status枚举值(枚举类型)。如果在调用async时使用了std::launch::deferred参数,那么函数将在future调用get()时在主线程中执行,而调用wait_for()会返回std::future_status::deferred,表示线程被延迟执行了。

2024-05-12 15:06:06 759 46

原创 std::async、std::future

std::promise通常与std::future一起使用,std::promise在一条线程中获得获得数据,而与之相关联的std::future(promise也有get_future()成员函数)可以在另一个线程中获得这些数据。std::launch::deferred:延迟调用,使用该参数,可以将线程入口函数调用的时间延迟到调用使用std::future的get(),wait()执行前。std::launch::async:在调用async时就调用线程入口函数,并且创建新的线程。

2024-05-11 18:21:38 560 27

原创 条件变量详解

条件变量是限制线程执行的一种机制,即在某些条件满足之前限制线程的执行。这种限制的目的,大多是为了减少线程之间信息闭塞,达到线程同步,从而提高线程之间的通信效率。线程中访问共享数据的代码常常带有一定的逻辑顺序(如数据的添加和删除)。而条件变量的目的就是将这些线程之间的代码的执行与逻辑顺序相吻合,从而避免线程不断的if判断是否达到执行要求。举个贴近的生活,你和你的好兄弟一起请求班上的好学生帮你们写作业,你好兄弟的作业先写,然后再写你的,着急的你一直询问好学生是不是轮到你了,这样会不会让好学生很烦!!!

2024-05-10 12:14:58 438 28

原创 单例类设计模式、call_once

std::call_once需要一个 std::once_flag(实际上是一个结构) 对象作为参数,该对象用于跟踪函数是否已经执行过。如果函数尚未执行,std::call_once就会执行提供的可调用对象(通常是一个函数或 lambda 表达式),并将 std::once_flag设置为已执行状态。如果函数已经执行过,std::call_once`则不会再次执行它。当第一次调用该该静态函数时,就会创建该类的唯一实例对象,当此后再调用该静态函数时,则返回已经创建的实例对象,不再创建新的实例对象。

2024-05-10 12:13:50 522 10

原创 多线程、mutex互斥量

我们可以将std::lock()与std::lock_guand结合使用,先使用std::lock()避免死锁问题,再用std::lock_guard()对象接管std::lock()的锁定状态。线程可以使用lock()函数获取锁,操作完成后再使用unlock()释放锁,这样其他等待锁的线程就可以使用lock(获取锁了,但只有一条线程会获取成功,其他线程将继续等待。这些不受限制的共享数据,实际上是有一定的风险的。如果保护的范围过窄,有些对共享数据的访问未被包含,就不足以保护共享的数据,产生一系列的问题。

2024-05-09 13:40:16 1084 21

原创 std::unique_lock详解

std::unique_lock的作用与std::lock_guard基本相同,也是用于管理对互斥量的锁定与解锁,但更加的灵活。std::defer_lock的作用是延迟锁的获取,表示unique_lock初始时不要尝试获取锁,而是当调用lock或者try_lock成员函数时再获取锁。当使用了std::try_to_lock后,如果没有获得锁,std::unique_lock并不会阻塞当前的线程,可以去执行一些其他的操作,等一段时间后再尝试获取锁,或者返回通知我们获取锁失败,然后继续执行代码。

2024-05-09 13:39:01 2721 3

原创 线程传参、线程ID

这种参数的传递,实际上是在新线程中复制一份相同的数据,即使参数设置为了引用,但实际上仅是复制了内容,主线程引用对象的销毁并不会对新线程产生影响。由于线程函数通常接受参数的复制版本(除非特别指定为引用),因此直接传递对象会导致线程函数操作的是对象的副本,而不是原始对象。传递智能指针智能指针作线程参数时,如果传递的是unique_ptr,那么应该使用移动语义std::move(),移动后,原始的unique_ptr对象将变为空指针,线程函数将拥有该指针的所有权。线程ID通常是一个整数,用于标识不同的线程。

2024-05-08 14:29:40 416 24

原创 线程创建、join、detach

为了保证新线程执行情况,还要使用thread成员中的join或者detach确保新线程执行的完全。join的作用是阻塞主线程的执行直到新线程执行完毕,就是让主线程等一等新线程。detach的作用是将线程从进程中分离出,转而在后台运行,这样即使主线程运行完毕,新线程也不会停止运行。进程的生命周期是和主线程相同的。所以,对于自主创建的线程要确保其在主线程结束执行前执行完毕或者保持主线程,否则就可能达不到预期的效果。如果类对象的成员中包含主线程中的变量的引用、指针等,就不要使用detach确保线程的执行。

2024-05-08 14:28:18 393 3

原创 并发与线程、进程基本概念

在单核CPU时期,CPU通过交替执行任务,快速的在多个任务之间切换,使得在短时间内每个任务都得到一定的执行时间,达到了多个任务一起执行的效果。但是这种切换是有一定的开销的,当从一个任务切换到另一个任务时,需要对本任务的数据,执行状况等进行保存,以便下次切换到本任务的时候能够恢复任务的执行状况,并继续执行。而线程只是一个进程中的不同执行路径,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。

2024-05-07 13:28:24 750 13

原创 智能指针三剑客:unique_ptr

unique_ptr是一种独占式的智能指针,有着指向对象的专属所有权。相同时间段内,一个对象只能被一个shared_ptr对象指向。当unique_ptr离开作用域或者被重新赋值时,会自动删除所指向的对象,避免内存的泄露。unique_ptr可以移动,但不可以复制。不允许两个unique_ptr指向同一个对象。和shared_ptr一样,unique_ptr如果定义时不初始化,默认为空。

2024-05-07 13:27:20 956 6

原创 智能指针三剑客:shared_ptr的使用

shared_ptr与weak_ptr对象占用的内存都是裸指针的两倍。当我们用shared_ptr对象生成weak_ptr对象时,weak_ptr对象中的指针就会指向shared_ptr指向的对象,另一个指向该 shared_ptr对象指向的控制块,就是说,指向同一个对象的shared_ptr对象和weak_ptr对象指向同一个控制块。这也说明了weak_ptr的生成要依赖shared_ptr对象的原因,因为weak_ptr对象并不能自主生成控制块,必须提供shared_ptr对象给出供它指向的控制块。

2024-05-06 11:24:44 416 2

原创 智能指针三剑客:weak_ptr

weak_ptr并不是独立的智能指针,weak_ptr主要被用来辅助share_ptr工作。由于weak_ptr的引用计数并不与指向对象的生命周期相关联,weak_ptr可以安全的访问一个由shared_ptr所管理的对象并不改变指向对象的内容。所以使用weak_ptr访问对象不需要担心意外延长其生命周期。除此之外,weak_ptr一般还被用于解决shared_ptr产生的循环问题。

2024-05-06 11:23:49 487 4

原创 智能指针三剑客:shared_ptr

在c++中,进行动态内存的分配通常使用new和delete操作符。我们在学习这一对运算符时,一定都听过要注意在使用完new分配到内存后,一定要使用delete手动释放内存,否则就会造成内存的泄露。智能指针就是用来避免这种情况的,智能指针实际上是一个类,它的使用类似于常规指针,但增加了自动内存管理的功能。它会自动删除其所指向的对象,防止内存泄露。而且,当在异常处理中使用动态分配到内存时,智能指针可以确保内存得到正确释放,即使在异常抛出时也是如此。

2024-04-14 23:20:05 1856 16

原创 可变参模板

可变参模板是C++11引入的一个功能强大的特性。英文名是Variadic Templates。其允许我们定义参数数量可变的模板函数和模板类,更加的提高了编写的灵活性和通用性。在可变参数模板中,参数的数量在编译时才会确定。这种机制多用于元组操作、函数封装、递归模板等需要处理不确定参数数量的场景。

2024-04-11 23:48:52 248 13

原创 模板的全特化和局部特化

模板的特化是一种在编译时根据特定类型提供特定实现的技术。与模板泛化相对,其帮助我们对有一定特殊性的类型进行特殊性的处理,支持了模板泛化处理中的偏差,从而提高了代码的灵活性和可重用性。特化可以分为全特化和局部特化(也叫偏特化)。一般我们将特化版本与泛化版本的代码放在同一个.h文件中。

2024-04-09 21:57:27 1079 12

原创 成员函数模板、模板的显式实例化和声明

为了防止在多个.cpp文件中相同用法使用模板类从而造成其生成多个可执行文件中出现过多的重复实例化的类模板,我们可以在其中一个.cpp文件的开头进行 实例化的定义 ,再在其他同样需要使用同类型实例化的.cpp文件中使用extern声明外部的.cpp的实例化的定义。除了虚函数,虚函数不可以成为模板函数,因为虚函数需要在子类中重新定义,但是因为没有具体的参数类型,无法生成其对应的代码,所以虚函数并不能同时为模板函数。类模板成员函数包括普通成员函数和成员函数模板,只有被我们调用了才会进行实例化,生成实例化版本。

2024-04-08 11:20:55 347 12

原创 函数/类模板详解

泛型编程是一种编程思想,其追求摆脱数据类型的束缚,通过将数据类型作为参数的处理,提高代码的通用性。模板是泛型编程的基础,它支持将数据类型作为参数,从而使得我们在处理具有相似性的对不同数据类型的处理时大大减少类代码量。模板在定义时并不会占有内存,而是在我们使用模板时针对我们的参数具体产生一个处理此类参数的函数/类,并在此时分配内存,这个过程就叫做模板的实例化。模板大致可以分为函数模板和类模板。两者有很多相似之处,但也略有不同。

2024-04-08 11:20:00 1051 6

原创 左右值及其引用详解

左值表达式的特点是有持久性,可以取地址,可以被我们赋值,也就是说具有可以被我们访问的存储单元,例如变量、对象成员等。对于左值引用和右值引用,我的理解是,左值引用是内存地址和内存内容的双重绑定,而右值引用更像简单的绑定内容,或者更干脆的将临时对象起个名字,将其变为一片持久的内存地址(这种给人一种二次利用的感觉,就好像是房东将即将到期出租房改为商品房把房产证转让了)。在C++11引入了右值引用的概念之后,我们可以将引用分为三种了,也就是左值引用和右值引用,以及常量引用(其实也是左值引用的一种)。

2024-03-15 01:29:56 983 2

原创 基类与派生类简记

本文为基类与派生类的各种关系的讨论,或者直接说我想记录一下的知识点。内容有些琐碎。派生类对象包含多个组成部分,一部分是继承于基类的成员,一部分是自己定义的成员,这两部分在内存也不一定是连续存储的。这样可以反映出一个基类指针可以指向派生类对象的原因,因为我们可以把派生类对象的基类部分当成是一个基类对象用。其实,当我们这样使用的时候,编译器进行了隐式的类型转换,也就是把派生类的基类部分隐式转换为基类对象,因此我们可以把派生类当做基类来用。

2024-03-14 00:37:47 484 1

原创 RTTI详解

RTTI就是Run Time Identification,翻译过来就是运行时类型识别。它提供了一种编译器在运行时通过类型信息使用基类的指针或者引用来检查其所指向对象的实际派生类型的方法。我们已经知道,一个基类指针可以指向基类对象和个个子类对象,那我们如何直到其实际指向的对象的类型呢,RTTI就给我们提供了这种功能。RTTI主要通过dynamic_cast运算符和typeid运算符来实现这个功能的。

2024-03-13 17:24:37 1321 1

原创 友元函数、友元类、友元成员函数

friend给我们提供一种访问类成员的方式,增加了代码的灵活性。但与此同时也破坏了类的封装性,降低了类的可靠性和可维护性。

2024-03-13 00:32:37 497

原创 多态性,虚函数详解

C++的多态性和虚函数密切相关。多态性可以说就是对虚函数而说的,就体现在具有继承关系的父类和子类之间,子类重写父类的成员函数,和虚函数动态绑定,根据实际指向类型在运行时确定调用哪个函数之中。

2024-03-12 22:22:23 1198 1

原创 继承/派生详解

继承是C++的重要特性之一。我们对原有的类进行功能上各有侧重的扩充,可以形成多种多样的新类。这样的新类叫作原本类的派生类、子类,而原本类也相对叫作基类,父类。提示:以下是本篇文章正文内容,下面案例可供参考提示:这里对文章进行总结:继承是面向对象程序设计的核心思想之一,我们应重视其与相关知识的结合,帮助我们更好的学习C++。

2024-03-11 23:18:45 614 1

原创 类,构造、析构、运算符重载

类和对象是C++面向对象程序设计的重要概念,是C++的特色和精华。精确的理解类的使用,对学习C++具有重要意义。提示:以下是本篇文章正文内容,下面案例可供参考一类简单来讲就是我们自己设计的数据类型。和C语言的结构体非常相似。具有继承性,封装性,多态性的特点。类具体化的结果就是对象,我们通过对象将类具体化,来帮我们解决具体的问题。类可以包含多种的成员变量和成员函数。它们有的供外界使用,有的仅在本类中处理数据,不供外界使用。因此我们在类的定义中使用不同的权限修饰符来表明这些成员的访问级别。

2024-03-09 22:24:56 1149

原创 四种类型转换

类型转换的允许,扩展了数据的用途和操作方式。在必要的时刻,我们可以使用,但要清晰地认识到它所带来的影响。提示:以下是本篇文章正文内容,下面案例可供参考强制类型转换能够抑制编译器报错。使用reinterpret_cast非常危险。使用const_cast也被有些人认为是设计缺陷。不建议在自己的代码中使用。

2024-03-03 17:13:32 1180 1

原创 vector容器用法详解

vector是C++标准库中的一个容器。使用vector,必须通过#include将其包含过来。提示:以下是本篇文章正文内容,下面案例可供参考vector可以理解成是一种集合或动态数组。我们可以把若干数据类型相同的对象储存在其中。与数组最大的区别就是vector储存在堆上,而数组储存在栈上,vector容器的长度可以动态的扩展,当我们增加长度时,编译器会释放原本的内存,找到一片更大的内存,将数据拷贝到现内存中。

2024-03-01 23:08:57 667 1

原创 迭代器用法详解

迭代器实际上是一种用来遍历容器元素的数据类型(作用类似与C语言的指针)。从此就可以看出,迭代器与容器的密切联系。我们知道,一些容器(如vector)可以通过[ ]来访问容器元素,但这种方式并不普遍,因为大多数的容器并不是数组实现的,也就不能用[]来访问容器元素。因此C++中就需要一种更加普遍的工具来提高效率,这就是迭代器。迭代器是一种数据类型,一种变量。它也有几种类型,输入迭代器,输出迭代器,前向迭代器,双向迭代器,随机迭代器。所以它支持++,--,>,=,

2024-02-29 14:09:02 2746

原创 string类详解

string类是C++标准库中的一个类,代表一个可变长字符串,功能也是对其的处理。与C语言中的char类型作用相似,但功能更加强大,使用也更加便捷,在c++环境中,更加适用。提示:以下是本篇文章正文内容,下面案例可供参考string s1;int a=9;定义string对象时,若未初始化对象,则对象保存内容为空。第二种和第三种都是将"hellow world"保存到内存中,但结尾中不包含/0。它们的作用一样,但建议用()的形式(因为使用=会带来隐式类型转换的问题)。

2024-02-27 22:39:10 507

原创 C语言基础 自定义函数

就像我们不可能穿100件衣服一样,多层函数嵌套也是极其占用空间的,因为多层的嵌套,中必然会包含很多的类型定义和形参变量,而在他们所在的函数空间释放前,它们和它们里层的函数内存空间都不会被释放。在基本的函数调用时,我们无法在函数中使用main函数中定义的变量,而我们在函数中经常要引用main函数中的数据,所以就有了参数列表。注意,即使函数没有参数,函数定义和函数调用时的()也不能省。也就是这个原因,main函数中定义的变量不能在我们定义的函数内使用,我们在自定义的函数中定义的变量也不能在main函数中使用。

2023-12-29 00:56:16 3237 1

原创 C语言基础 指针的详细解析

指针是C语言的一个重要概念和特色,对于C语言的学习来说也是重点和难点。

2023-12-25 00:46:26 1238

原创 C语言基础getchar和putchar详解

由于只对单个字符进行处理,大大限制了putchar和getchar的使用范围。常在处理一些特殊字符时使用。

2023-12-19 00:25:44 591 1

原创 C语言入门:scanf和printf解析与比较

pritnf与scanf属于C语言中最常用的函数,都属于输入输出函数,是头文件stdio.h的库函数,下面我们来一起探究一下他们的用法和对比。printf和scanf的用法虽然十分简单,但依然有许多容易忽略的小细节。

2023-12-17 22:21:45 849 2

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除