- 博客(28)
- 收藏
- 关注
原创 C++基础:enum class作用域枚举 (C++11)
enum class 是C++11引入的一种改进的枚举机制,主要改进了传统的enum类型的作用域控制问题, 故也被称为作用域枚举(scoped enumerations)。那么,他到底解决了什么问题呢?猜到这个代码出了什么问题了吗?没错,当你尝试编译的时候,他会给你报一个write重定义的错误。实际上,enum类型在C++的体系中完全属于特例。
2024-10-06 16:19:38 335
原创 分布式理论:拜占庭将军问题
拜占庭将军问题是对分布式共识问题的一种情景化描述,由兰伯特于1082首次发表《The Byzantine Generals Problem》中提及,它是分布式领域最复杂的一个容错模型, 它描述了如何在存在恶意行为的情况下使分布式系统达成一致,了解拜占庭问题对于掌握分布式共识问题具有深刻意义。这个算法虽然可以保证无论叛将如何捣乱,我们都能做出一行的行为,但是这是有前提的。在兰伯特的论文中指出:如果叛将人数为m,将军人数不能少于3m+1,只有这样,口信型拜占庭将军之解才能生效。或者说,
2024-10-03 12:51:22 1420 2
原创 Linux线程标识获取
这个函数提供了C++标准库级别的线程ID,可以很好和C++的 std::thread 库配合,但是很不幸,std::thread::get_id()的值也是进程内有效的,如果你没有跨进程唯一线程标识的需求,使用该函数也是很不错的选择。实际开发中,我们有多种方式来获取线程标识。该系统调用的返回值为 pid_t, 其值一般为一个小整数,它直接代表着内核的任务调度id, 该标识是全局唯一的,多个进程中的不同线程的标识也是唯一的,且 pid_t 的分配方式为轮询分配,短时间启动销毁的多个线程也会获取到不同的标识。
2024-09-30 15:28:55 471
原创 C++基础:折叠表达式(C++17)
C++17 引入了一种新的语法特性,叫做折叠表达式,它允许编译器在模板参数包展开时进行元编程操作。折叠表达式的引入极大地简化了元编程代码,使其变得更为直观和简介。
2024-09-07 15:04:17 582
原创 Linux系统编程:监视文件系统变化(inotify)
你是否有过这样的需求,监控某个文件的修改情况,一旦某个文件的内容被修改你的进程就能观察到,对准对情况进行文件备份之类的操作。在Linux 环境下,内核提供了inotify API 用于监控文件系统的情况,可以用于监视文件的创建,修改,删除等事件。inotify用于当内核发生文件系统相关的某种事件后,用于通知用户空间,方便用户做出具体的操作。inotify 可以监控单个的文件,也可以监控整个目录,当一个目录被监控时,inotify会返回关于该目录本身及其内部文件的事件。
2024-08-22 15:01:59 917
原创 Cmake基础教程--第2章:打印信息和变量操作
CMake项目时基于一个名为 CMakeLists.txt 的文件来构造的,注意大小写不能拼写错误。我们在CMakeLists.txt 中使用CMake Language来编写项目的构建逻辑,其语法类似与命令式编程语言。执行cmake时,会从根CMakeLists.txt 文件开始执行。
2024-08-15 21:59:08 833
原创 Cmake基础教程--第1章:初识cmake
从本篇文章开始,我会出一系列文章,致力于Cmake工具的学习使用。阅读本文章之前,作者默认读者会使用基础的命令行工具且具有C++基础。
2024-08-07 22:05:56 742
原创 C/C++基础:宏
(a > b)?return 0;(a > b)?return 0;(a > b)?(a > b)?a : b }?(a > b)?a : b }但是如果这个宏的替换列表很长呢?// 这是正确的实现// 这是正确的实现 # define max(a , b) {
2024-07-25 00:19:11 1150
原创 C++基础 auto 和 decltype的区别
这意味着你不需要显式写出变量的类型,编译器会根据你赋予的初始值来确定类型。这对于复杂类型、模板编程或是避免重复冗长的类型名称尤其有用,可以提高代码的可读性和编写效率。所以,decltype(x) 是变量名的规则,而 decltype((x)) 是表达式的规则,井水不犯河水,参数如果是变量名,就返回其声明的类型;除此之外,decltype还可以将表达式用()包裹,此时decltype的推导就不单单是表达式所属实体的类型,而是会继续通过表达式来推断出值类别来判断引用属性,
2024-06-04 20:43:56 343
原创 std::shared_ptr使用new和make_shared两种方法构造关于访问权限的区别
C++11给开发者提供了十分好用的智能指针 std::shared_ptr ,合理的使用智能指针可以一定程度的避免内存泄漏问题。int一般来说,这两个构造方法并无太大的区别,但我们更建议使用 make_shared 来创建智能指针,其在一些情况下效率更优。但今天开发时,遇到了无法使用 make_shared 而 new 操作正常的情况,本博客即记录该现象。
2024-03-10 13:57:23 702 1
原创 cmake基础教程(下)
因为 main.cpp 中调用 a.cpp 和 b.cpp 中实现的函数,我们这里将 dir1/ 和 dir2/ 下的源码编译为静态库,再链接到 main.cpp 生成的可执行文件中。同时,我们之前并没有去区分编译出的文件是release版本还是debug版本,这里我们希望能指定编译的版本,并且将对应版本的动态库放置到对应的目录下。这里注意,我们在使用静态库或者动态库的时候,除了需要库文件以外,还需要头文件,所以这里我们还需要把头文件所在的目录添加进来。用于将指定的动态库或者静态库链接到指定的可执行文件。
2024-03-07 13:00:43 1005 1
原创 cmake基础教程(上)
我们希望在顶层的 CmakeList.txt 中接着调用src/下的 CMakeLists.txt 继续去构建项目,并且将最终生成的可执行文件安装到bin/下。因为构建的时候会产生大量的中间文件,一般我们会先创建一个build文件夹,在build文件夹中使用cmake命令。执行过会可以发现,build出现了大量的中间文件,并且生成了MakeFile,在build目录中使用命令。在实际的项目开发中,我们为了让项目的结构清晰,一般会有固定的模式来组织目录,下面给出一个典型的结构.
2024-03-02 17:49:43 859 1
原创 C++基础:异步操作(std::async, std::future, std::packaged_task, std::promise)
std::packaged_task是一个将任务和future绑定在一起的模板,是一种对任务的封装,可以通过方法std::get_future来获得绑定的函数的返回值类型的future。C++11之后提供了实用的thread库,但 thread 在 join 的时候并不能获取到任务结束的返回值,对于刚刚介绍的异步操作async,其返回值为一个std::future对象,而不是一个确定的值,当你需要使用这个值的时候,可以调用future的get方法,get会一直阻塞,直到future就绪,然后返回该值。
2024-03-01 13:43:51 410
原创 C++基础:右值引用,移动语义和完美转发
顾名思义,右值引用就是对右值引用的类型,通过右值引用,右值的生命周期会获得延长,只要右值引用的变量还活着,该右值临时量就会一直活下去。其最终会输出5,换言之,左值引用也是引用,如果打印i,ref1,ref2的地址,会发现三者地址也是一样的,对ref2的修改也会改变i本身的值。forward 完美转发实现了参数在传递过程中保持其值属性的功能,即若是左值,则传递之后仍然是左值,若是右值,则传递之后仍然是右值。在C++11以后,C++所有的值都必属于左值,将亡值,纯右值三者之一,其中,将亡值和纯右值都属于右值。
2024-02-25 19:23:31 422 1
原创 C++基础:智能指针
在创建智能指针时,可以给对象指定一个删除器,当智能指针的引用计数为零时,会自动调用该删除器来释放对象的内存,比如我们用std::shared_ptr来管理动态数组,std::shared_ptr的默认删除器不支持删除数组对象,我们就可以指定删除器。std::shared_ptr使用引用计数来保证浅拷贝的内存释放问题,每一个shared_ptr的拷贝都会指向同一块内存,只有当最后一个shared_ptr拷贝析构的时候,才会将其指向的内存释放。相对于原始指针来说,智能指针不需要手动释放内存,其内存会自动释放。
2024-02-24 11:10:09 1020
原创 C++面向对象基础:设计模式(下)
代码解释:上述代码中,如果我们希望创建ExportXm, ExportJson或者ExportTxt类的对象并使用其Export方法,我们可以创建一个其对应的工厂类实例并用于初始化总工厂ExportData对象,然后就可以通过ExportData实例来使用你需要的类的方法。抽象工厂是工厂方法模式的一种变种,为了缩减工厂实现子类的数量,不必给每一个产品分配一个工厂类,可以将产品进行分组,每组中的不同产品由同一个工厂类的不同方法来创建。为每一个子类建立一个对应的工厂子类,这些工厂子类实现同一个抽象工厂接口。
2024-02-21 21:32:35 804
原创 C++面向对象基础:设计模式(中)-- 单例模式详解
当持有锁的线程执行到new操作时,若其仅仅执行到1->2但还并未调用构造函数,此时会出现这样的情况:_instance指针已经拿到了new的返回值,此时已经不是nullptr,但因为还没有调用构造函数此时的_instance还没有实际的数据,而处于其他地方的线程可能会在这个时候直接将_instance返回并使用,这会导致严重的线程安全问题,这绝不是我们希望发生的。这个设计模式的定义实在是简单明了,也是最常用的设计模式,用该设计模式可以定义一个类仅会有一个实例对象,并且可以全局访问。注意这里实现的几个细节。
2024-02-19 12:23:40 887 1
原创 C++面向对象基础:设计模式(上)
通过该设计模式,只要DataCenter类的CalcTemperature方法发生改变,我们都可以调用Nodify方法使得所有订阅了该类的终端发生变化,是否订阅也取决于客户,DataCenter不关心是否有类订阅了自身。如以上代码,使用模版方法模式,我们可以在保证Show方法总体结构不变的情况下,通过子类重写父类的protected方法,来改变Show的部分执行过程。设计模式可以认为是解决问题的固定套路,是满足设计原则的情况下,慢慢迭代出来的套路,学习设计模式,可以让我们深入理解面向对象的思想。
2024-02-15 15:29:16 1060 2
原创 git push 推送代码出错ssh: Could not resolve hostname gitee.com: Temporary failure in name resolution
师兄说过:重启解决百分之99的问题,师兄诚不欺我。遇到奇怪的错误,都不妨关机重启试试,说不定就解决了呢?
2024-02-13 23:38:19 1075 1
原创 Git基础教程
Git和GitHub或者Gitee并不是一种东西,GitHub是基于Git的代码托管服务平台,而Git则是分布式版本控制系统。可以把Gitee看成一个百度云盘,我们可以把git仓库推送至Gitee,或者把Gitee的git仓库拉取下来,对比百度云盘,Gitee的功能则可以和Git无缝衔接。
2024-02-06 11:22:13 959 1
原创 C++基础-va_list的使用
va_list定义于头文件中,是用于处理C语言风格变参函数而使用的一种对象类型,va_list类型的变量是指向参数的指针,通过指针运算来调整访问的对象,其主要使用如下几种宏来进行操作.
2024-01-17 23:12:53 797
原创 略有小成-ffplay数据读取线程分析(上)
该部分主要是通过函数avcodec_find_decoder来查找所需的解码器,如果用户指定了解码器,则会设置全局变量forced_codec_name的值,并通过avcodec_find_decoder_by_name来查找指定的解码器。这里就是通过流中的参数来设置窗口的相关宽高等信息。通过了前面的步骤,文件成功打开,获取了流的基本信息,并成功选择的需要的流进行读取,该部分会根据所选的流来打开对应的解码器。如果设置了相关流,由于av_find_best_stream的第三个参数,会查找用户指定的流。
2023-12-14 20:53:09 120 1
原创 C++网络编程-IO的阻塞与非阻塞
对于函数recv来说,当其无法立即从缓冲区中读取数据时,会返回-1,并且将errno的值置为EAGAIN,表示此次IO操作并非出错,而是缓冲区无数据。如果调用recv时,缓冲区中不存在数据,该线程会被挂起,只有等到得到结果后才会返回,即线程会阻塞到recv函数,不会继续向下执行,直到缓冲区被写入数据。但是,如果进行读操作时,如果内核缓冲区无数据,此时就会牵扯到IO的阻塞与非阻塞。在这种操作中,操作系统会检查内核缓冲区有无需要的数据,如果有数据,就把内核缓冲区的数据拷贝到用户空间,供用户的应用程序使用。
2023-12-05 18:57:53 144 1
原创 初窥门径Ⅱ-ffplay-FrameQueue详细解析
写队列时,我们向队列写入一个新的帧的时候,总是会同时更新写索引。而读队列时,读取一个可读帧和更新读索引是独立的操作, 可以只读取帧而不更新索引, 或者只更新索引而不读取帧。调用frame_queue_peek_readable获取可读的frame根据是否需要跟新读索引调用frame_queue_next来更新读索引。
2023-11-30 21:05:58 295 1
原创 初窥门径-ffplay-PacketQueue结构体详细分析
PacketQueue结构体在之前的文章中已经有所介绍,这里再重复一遍,已经熟知的可自行跳过。//数据存储缓存区域//包的数量, 即队列的元素数量int size;//队列所有元素的数据大小的综合//队列所有节点播放时间总和//用户请求退出标志int serial;//播放序列号ffplay使用MyAVPacketList来保存解封装后的数据,而使用PacketQueue来存储MyAVpacketList数据。
2023-11-24 16:57:57 146 1
原创 初来驾到——ffplay总体框架和核心数据结构分析
serial用于标记当前节点的播放序列号,主要用来区分是否是连续数据,每一次进行seek操作,都会使得serial做+1的操作,以区分不同的播放序列. 每次 seek 以后 以前的队列中的东西当然就不能用了呗 应该放弃的放弃 要free 的 free。ffplay中,视频,音频,字幕有各自的解码线程和播放线程,故ffplay中其实也存在着对应的三种frameQueue,每个队列都有一个读端和写端,读端位于播放线程,而写端自然而然在解码线程接受数据。AVFifo 是一个按字节存储数据的结构体。
2023-11-22 19:21:29 273
原创 C++基础--const限定符
值得注意的是,用const来修饰指针本身,和指向常量的指针是有着巨大区别的,指针被const修饰之后并不意味着该指针失去了修改其对象的值的能力(由所指对象的类型决定),而是指针本身的指向无法修改。注意,在默认的情况下,const对象被设定在仅在本文件内有效,const修饰的全局变量在其他的文件中也是不可见的,当在多个文件中使用同名的const变量时,其实是在不同的文件中定义了独立的变量。与其他用const修饰的成分一样,指向常量的指针无法修改其指向对象的值,同时,只有通过指向常量的指针,才能够来存储常量。
2023-07-18 19:04:44 100 2
原创 音视频开发中视频的相关概念
同样,视频的分辨率也会影响到视频的存储大小,尽管视频的时长相同,但高清视频内存依旧会显著大于标准分辨率视频。由于视觉暂留效应,当视频的帧率达到10~12帧后,画面就会呈现出连续的效果,且相同条件情况下,视频的帧率越高,视频给人的感觉也就越流畅。一般来说,视频质量和网络带宽占用是矛盾的,通常情况下视频流占用的带宽越高则视频质量也越高,若要要求高质量的视频效果,那么需要的网络带宽也越大。帧:简单来说,就是视频中的每一个画面的图片,视频都是由无数张连续播放的图片组成的。每一张图片都可以认为是一帧。
2023-05-01 20:54:32 63
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人