- 博客(129)
- 收藏
- 关注
原创 设计模式之模块方法
模板与方法应该是最常使用的设计模式,在GOF(设计模式)中的定义:定义一个操作中的算法的骨架 ,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2024-11-04 22:08:38 341
原创 面向对象的设计原则
使用封装来创建对象之间的分界层,让设计者可以在分解层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。减少系统中的各部分的依赖关系,从而实现“高内聚”,“松耦合”的类型设计方式。而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。不将变量类型声明为某个特定的具体类,而是声明为某个接口。类模块应该是可扩展的,但是不可修改。
2024-11-03 22:37:58 176
原创 理解为什么要有C++设计模式
抽象:更高层次来讲,人们处理复杂性有一个通用的技术,即抽象。由于不能掌握全部的复杂对象,我们选择忽视它的非本质细节而去处理泛化和理想化了的对象模型。每一个模式描述了一个在我们周围不断重复的问题以及该问题的解决方案的核心,这样,就能一次有一次地使用该方案,而不必做重复劳动。分解:人们面对复杂性有一个常见的做法:即分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单问题。但是我们通过C++的特性多态来进行操作的话,我们的操作步骤和代码量会明显的减少;
2024-10-31 23:22:00 405
原创 ffmpeg重采样
ffmpeg重采样指的是可以将一个固定频率的音频转换为任意格式的音频,比如改变音频的采样率或者声道,这种操作简称为重采样。但是在重采样的过程中也会有一些数据丢失的过程,主要原因是在采样会会进行向上对齐,所以会出现转换后大小不一致的情况。在进行重采样操作时,另开一个线程来完成此工作。
2024-08-11 21:51:33 415
原创 ffmpeg解析pcm文件进行播放
初始化音频子系统是使用 SDL 播放音频之前的一个必要步骤。如果你不进行初始化,试图使用音频功能可能会导致未定义的行为或错误。初始化时 SDL 会尝试检测并报告任何潜在的问题,如音频设备不可用或驱动程序错误。当进行传参并进行设置回调函数后,线程就会不停歇的进行调用回调函数,知道线程结束。初始化过程中可以设置音频输出的基本参数,如通道数、采样率、格式等。SDL 需要为音频设备分配资源,比如设置缓冲区大小、采样率等。初始化过程确保 SDL 使用正确的驱动程序与音频硬件通信。这些设置对于播放音频是必需的。
2024-07-24 22:39:36 437
原创 第一个ffmpeg程序
在使用 FFmpeg 进行音视频处理时,有时需要读取或者写入来自外部设备(如摄像头、音频接口)的数据,这时就可以使用 avdevice_register_all 来初始化并注册这些设备,以便后续可以通过 FFmpeg 的统一接口来进行数据的读取和写入。总结来说,avdevice_register_all 的作用就是在 FFmpeg 应用程序中,初始化并注册所有可用的音视频设备,使得这些设备可以被 FFmpeg 使用。当我们进行点击按钮时,会触发按钮信号并进行调用ffmpeg的一些方法进行录音操作。
2024-07-08 23:52:13 496
原创 docker八大架构之应用数据分离架构
数据分离架构是指应用服务(应用层)和数据库服务(数据层)使用不同的服务器来进行操作,如下边的两个图所示。当访问到应用层后,如果需要获取数据会进行访问另一个服务器,从而避免在同一服务器进行操作,避免单机架构的缺点。
2024-05-12 22:44:27 231 2
原创 docker八大架构之单机架构
单机架构指的是应用服务和数据库服务公用同一台服务器。如下边两个图所示,当我们进行购物时,所有的物品信息和用户信息都是在同一个服务器下进行运行的,之所以称为单机架构就是因为它所有的操作是在同一台服务器上进行的。
2024-05-12 22:19:05 427 2
原创 docker是干嘛的?
它利用容器化技术,将应用程序及其依赖项打包到一个称为容器的可移植容器中。这使得应用程序能够在几乎任何环境中运行,而不受所运行的操作系统和硬件的限制。总之,Docker使得开发人员和运维团队能够更轻松地构建、交付和运行应用程序,同时提高了开发和部署的效率。便携性: 可以在不同的环境中轻松部署相同的应用程序,而不必担心环境差异导致的问题。版本控制: 可以轻松地创建、共享和管理容器镜像,确保开发、测试和生产环境的一致性。快速部署: 可以快速地启动和停止容器,从而加快应用程序的部署速度。
2024-05-12 22:18:09 793
原创 【MySQL】视图
视图是一个虚拟的表,其内容由查询来进行定义。视图的数据变化会影响基表,基表的数据变化也会影响视图。如果我们频繁的进行表查询的时候,我们可以通过视图来进行查询,并且,修改视图后原表也会变化哦。注意,视图不是一个真正的表,但是我们可以使用和表一样的操作来查询它。注意,视图名不要和基表的名字相同。下边我们创建两个表,并插入数据。
2023-12-21 22:28:20 742 3
原创 【MySQL】表的内连和外连
内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。创建两个表并插入数据。
2023-12-07 20:30:02 496 3
原创 【MySQL】复合查询
单行子查询是指子查询只返回单列,单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询则是指查询返回多个列数据的子查询语句。在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。– 给自己的表起别名,因为要先做笛卡尔积,所以别名可以先识。自连接是指在同一张表连接查询。现有一个员工信息表emp。返回一行记录的子查询。
2023-12-07 20:16:28 258
原创 【MySQL】内置函数
思路是通过substring函数先将字符串中第一个字符截取出来,使用lcase进行处理之后,再与剩余的部分进行拼接。通常来讲在服务器中存储的密码是以这种加密方式存储的。向上取整函数的上,表示的是正无穷方向的上。向下取整同理,下指的是负无穷的方向。输出两分钟内新插入的数据。
2023-12-05 20:53:59 716 2
原创 【MySQL】聚合函数和分组(查找)
where是过滤表中数据的,而having是过滤分组数据的。在分组之前需要先通过where来拿到所要用到的数据。分组聚合主要使用的是 group by 和 having子句。分组聚合需要注意的是要先进行分组,然后再聚合。在select中使用group by 子句可以对指定列进行分组查询。3.SALGRADE:工资等级表。2.DEPT:部门表。
2023-12-05 16:59:21 173
原创 【C++】设计模式之——建造者
建造者模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。首先先大体了解一下,建造者模式是什么意思,它是怎么实现的?建造者模式主要用于构建复杂问题。
2023-10-03 21:54:30 1179 10
原创 【C++】类型转换
而使用dynamic_cast进行向下转型则是安全的,如果父类的指针(或引用)指向的是子类对象那么dynamic_cast会转换成功,但如果父类的指针(或引用)指向的是父类对象那么dynamic_cast会转换失败并返回一个空指针。上述代码中,如果传入func函数的是子类对象的地址,那么在转换后pb1和pb2都会有对应的地址,但如果传入func函数的是父类对象的地址,那么转换后pb1会有对应的地址,而pb2则是一个空指针。dynamic_cast用于将父类的指针(或引用)转换成子类的指针(或引用)。
2023-10-02 15:09:12 163
原创 【C++】单例
new和delete默认调用的是全局的operator new函数和operator delete函数,但如果一个类重载了专属的operator new函数和operator delete函数,那么new和delete就会调用这个专属的函数。将该类的构造函数设置为私有即可,因为子类的构造函数被调用时,必须调用父类的构造函数初始化父类的那一部分成员,但父类的私有成员在子类当中是不可见的,所以在创建子类对象时子类无法调用父类的构造函数对父类的成员进行初始化,因此该类被继承后子类无法创建出对象。
2023-10-02 09:43:13 186
原创 【C++】智能指针
上述程序是没有问题的,两个结点都能够正确释放。当智能指针对象的生命周期结束时,所有的智能指针默认都是以delete的方式将资源释放,这是不太合适的,因为智能指针并不是只管理以new方式申请到的内存空间,智能指针管理的也可能是以new[]的方式申请到的空间,或管理的是一个文件指针。需要注意的是,智能指针就是要模拟原生指针的行为,当我们将一个指针赋值给另一个指针时,目的就是让这两个指针指向同一块内存空间,所以这里本就应该进行浅拷贝,但单纯的浅拷贝又会导致空间被多次释放,因此根据解决智能指针拷贝问题方式的不同,
2023-10-01 18:34:49 218
原创 【C++】异常
实际中很多公司都会自定义自己的异常体系进行规范的异常管理。公司中的项目一般会进行模块划分,让不同的程序员或小组完成不同的模块,如果不对抛异常这件事进行规范,那么负责最外层捕获异常的程序员就非常难受了,因为他需要捕获大家抛出的各种类型的异常对象。因此实际中都会定义一套继承的规范体系,先定义一个最基础的异常类,所有人抛出的异常对象都必须是继承于该异常类的派生类对象,因为异常语法规定可以用基类捕获抛出的派生类对象,因此最外层就只需捕获基类就行了。
2023-10-01 14:09:44 178
原创 【C++】function包装器和bind包装器
function是一种函数包装器,也叫做适配器。它可以对可调用对象进行包装,C++中的function本质就是一个类模板。Ret:被包装的可调用对象的返回值Args:被包装可调用对象的形参类型包装示例function包装器可以对可调用对象进行包装,包括函数指针(函数名)、仿函数(函数对象)、lambda表达式、类的成员函数。//仿函数public:class Pluspublic:int main()//1.包装函数指针(函数名)//2.包装仿函数(函数对象)
2023-09-30 11:07:21 207 1
原创 【C++11】多线程
主线程创建新线程后,也可以调用detach进行将线程和主线程分离,分离后,新线程会到后台运行,其所有权和控制权将会交给C++运行库,此时,c++运行库会保证当线程退出时,其相关资源能够被正确回收。线程函数的参数是以值拷贝的方式拷贝到线程栈空间中的,就算线程函数的参数为引用类型,在线程函数中修改后也不会影响到外部实参,因为其实际引用的是线程栈中的拷贝,而不是外部实参。在没有对临界资源加锁的时候,由于是多个进程同时进行,这时,不能同步的,正确的完成我们的任务,此时我们就需要给临界资源进行加锁。
2023-09-29 22:12:08 1303
原创 【Linux】线程池
简单的来说,线程池的本质就是使用空间换取时间,例如一个程序本来就需要10个字节,但是它申请内存的时候申请了20个字节,为它以后使用,这样在下次使用的时候就不需要再次申请内存了,从而牺牲了空间节省了时间。线程池内逻辑实现,这里我们锁线程共享的变量放到构造器里头直接初始化,其中,我们还是用了队列来存线程数据,如果有线程进入,我们就会将其线程的操作方法放入队列中,当运行后,我们再将其取出。下面我们实现一个简单的线程池,线程池中提供了一个任务队列,以及若干个线程(多线程)。主函数,用于控制多线程。
2023-09-28 20:33:32 263
原创 【Linux】POSIX信号量
我们要先进性申请资源,后申请锁,因为如果先申请锁的画,如果这时的信号处于满的状态,那么此时我们的锁就会一直卡的,当其他线程进行申请时,就会一直处于堆积的状态。每个执行流进入临界区时,都会提前申请信号量,申请成功后就有了操作特定临界资源的权限,当操作完毕后,就会释放对应的信号量,同样,如果申请失败也会被挂起。当执行流就行申请信号量失败时,也就是说临界资源已经全部申请空了,此时该执行流就会在对应的信号量的等待队列中当中进行等待,直到有信号量被释放时再被唤醒。
2023-09-27 20:49:23 224
原创 【Linux】生产者和消费者模型
生产者和消费者彼此之间不直接通讯,而通过这个容器来通讯,所以生产者生产完数据之后不用等待消费者处理,直接将生产的数据放到这个容器当中,消费者也不用找生产者要数据,而是直接从这个容器里取数据,这个容器就相当于一个缓冲区,平衡了生产者和消费者的处理能力,这个容器实际上就是用来给生产者和消费者解耦的。其中,所有的生产者和消费者都会竞争式的申请锁,因此生产者和生产者、消费者和消费者、生产者和消费者之间都存在互斥关系。生产者和生产者、消费者和消费者、生产者和消费者,它们之间为什么会存在互斥关系?
2023-09-27 15:55:09 309
原创 【Linux】线程安全
其实在多线程中,几乎我们访问到的临界区和临界资源较多,所以我们通过多线程就可以很简单的构造这么一个环境。如下代码:此时我们相当如实现了主线程和新线程之间的通信,其中全局变量const称之为临界资源,因为他被多个执行流共享,而主线程中的printf和新线程中的const++称之为临界区,因为这些代码对临界资源进行了访问。当多个线程同时多一个临界资源进行访问修改的时候,那么此时就可能会导致不一致的问题,解决该问题的方案叫做互斥,互斥的作用就是保证任何时候只有一个执行流通过临界区进行对临界资源访问。我们可以自
2023-09-27 14:31:13 625
原创 【Linux】详细介绍Linux重入不可重入带例子
在Linux中,重入性指的是一个函数可以安全地在同时被多个线程或进程调用时正确地执行。不可重入性则表示一个函数在被并发调用时可能会导致不确定的行为或数据损坏。
2023-09-25 15:07:34 203 3
原创 【Linux】Linux多线程
LWP表示轻量级进程的ID,代表对线程ID,我们可以看出,每个线程的ID都是不一样的,实际操作系统调用的时候都是调用的LWP,而并非PID,只不过我们之前接触到的都是单线程进程,其PID和LWP是相等的,所以对于单线程进程来说,调度时采用PID和LWP是一样的。我们从图中可以看出,他们的 PID 和 PPID都是一样的,这说明它们属于同一个线程,但是他们的LWP是不相等的,从图中我们可以看到有五个线程,其中,第一个线程为主线程,当主线程异常退出时,剩余的进程也全都会随之退出。
2023-09-25 14:38:19 211
原创 【C++】C++11——lambda表达式
说明一下: 实际当我们以[&]或[=]的方式捕获变量时,编译器也不一定会把父作用域中所有的变量捕获进来,编译器可能只会对lambda表达式中用到的变量进行捕获,没有必要把用不到的变量也捕获进来,这个主要看编译器的具体实现。这样一来,调用lambda表达式时就不用传入参数了,但实际我们只需要用到变量a和变量b,没有必要把父作用域中的所有变量都进行捕捉,因此也可以只对父作用域中的a、b变量进行捕捉。使用该修饰符时,参数列表不可以省略。:在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。
2023-09-23 09:51:52 136 3
原创 【Linux】进程信号
C/C++程序会崩溃,是因为程序当中出现的各种错误最终一定会在硬件层面上有所表现,进而会被操作系统识别到,然后操作系统就会发送相应的信号将当前的进程终止。
2023-09-23 08:48:41 517 1
原创 【C++】C++11——可变参数模板和emplace
可变参数包的个数可以为0,也可以为N返回类型 函数名(Args ...args)//函数体{}模板参数包Args和函数形参参数包args名字可以任意指定,并不是强制的。
2023-09-23 08:48:32 602
原创 【C++】C++11——构造、赋值使用条件和生成条件
我们可以看出,此时输出的为移动构造,当我们将person类中的析构拷贝构造等复原的时候,这时就不满足条件了,也就调用的为深度拷贝了。在有一些条件下,我们的默认构造总是默认生成失败,为了解决这个问题,C++11推出了关键字default来强制将其生成。从以上代码我们可以看出,我们person类中只有一个构造函数,这时是满足我们默认生成的条件的。在这里,移动构造和移动赋值并不是说没有写就会自动生成,而是需要一定的条件支持下才会生成。默认生成的移动构造和移动赋值做的什么赋值。
2023-09-23 08:48:15 280
原创 【C++】左值和右值
这里需要说明的是,对于返回局部对象的函数,就算只是调用函数而不接收该函数的返回值,也会存在一次拷贝构造或移动构造,因为函数的返回值不管你接不接收都必须要有,而当函数结束后该函数内的局部对象都会被销毁,所以就算不接收函数的返回值也会调用一次拷贝构造或移动构造生成临时对象。右值引用需要是确定的类型,而万能引用是根据传入实参的类型进行推导,如果传入的实参是一个左值,那么这里的形参t就是左值引用,如果传入的实参是一个右值,那么这里的形参t就是右值引用。通常,左值对应于具名的变量、被引用的对象以及某些表达式的结果。
2023-09-22 08:32:00 449
原创 【C++】C++11——列表初始化及decltype
内置类型注意: 用大括号对new表达式初始化时不能加等号。自定义类型创建对象时也可以使用列表初始化方式调用构造函数初始化。比如:C++11中新添加了容器,该容器没有提供过多的成员函数当我们使用auto进行定义一个变量,来进行接收列表初始化过的变量时,我们发现它的类型为类型,使用的方式查看该变量的类型。initializer_list容器没有提供对应的增删查改等接口,因为initializer_list并不是专门用于存储数据的,而是为了让其他容器支持列表初始化的。比如:C++98并不支持直接用列表
2023-09-21 10:03:27 479 1
原创 【C++】哈希位图和布隆过滤器
假设布隆过滤器使用三个哈希函数进行映射,那么“张三”这个昵称被使用后位图中会有三个比特位会被置1,当有人要使用“李四”这个昵称时,就算前两个哈希函数计算出来的位置都产生了冲突,但由于第三个哈希函数计算出的比特位的值为0,此时系统就会判定“李四”这个昵称没有被使用过。当元素不存在时,对应位置的位值为0。我们这里可以大概估算一下,如果使用3个哈希函数,即k的值为3,l n 2 的值我们取0.7,那么 m 和 n的关系大概是m = 4 × n ,也就是布隆过滤器的长度应该是插入元素个数的4倍。
2023-09-17 21:20:56 1162 56
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人