关于c++:FFmpeg连载1环境搭建

前言之前笔者从事安卓开发的时候想要学习音视频实际,脑子外面想的是要是有专门针对安卓开发的FFmpeg教程就好了。缓缓地发现这个想法很不靠谱,因为那时对于音视频的相干教程原本就少,如果还要是针对安卓的就百里挑一了。 起初为了学习FFmpeg,笔者也是断断续续的,从音视频的根底材料开始,从FFmpeg编译到实际,心愿通过本人的学习能够一点一点地揭开FFmpeg的神秘面纱,直到明天笔者只敢说仅是音视频开发大军中的一个入门老手而已,虽说本人摸索挺久,但仍旧难以进阶,我想其中有两个次要的起因,一是短少仙人指路,二是断断续续,不足系统性的学习总结。 学习最重要的是死记硬背,如果你心田想要学习,然而又以没有齐全针对性的教程材料为由,最初你会发现自己还是想的比做的多,还不如不想... 对于FFmpeg这货色,你说它难,其实它也就那么一回事,你说它简略,有数人在编译阶段就被迫放弃了,或者它难的不是它自身,更多学习者一个敢于开始的勇气和坚持不懈的保持吧。 为了让老手能够更疾速地入门FFmpeg,笔者将开始连载对于FFmpeg相干文章,次要波及音视频解封装、音视频解码、音视频编码、音频重采样等相干知识点。 在本系列文章的最初,可能会以一个小小的实际作为收尾,这个实际的内容大体是: 1、输出多个mp3文件,解码成pcm,而后进行重采样,拼接合并编码成aac音频; 2、输出多个mp4文件,提取出视频解码成yuv,而后拼接合并编码成h264; 3、将1中的aac音频和2中的h264视频合并成新的mp4文件。明天咱们次要是先把环境搭建好,毕竟千里之行始于足下。 笔者环境笔者应用的范例环境了Mac零碎,开发工具是CLion。 装置FFmpeg对于引入在PC上引入FFmpeg的话还是比较简单的,能够通过命令行工具进行装置,而后将相干库提取解决即可,又或者能够间接应用源码间接编译相干库都能够。然而如果要想把FFmpeg继承到安卓中去就要应用NDK教程编译了,对于如何应用NDK教程编译FFmpeg童鞋们能够去翻我之前的文章,或者前面有工夫我在整顿一份都行。 鉴于FFmpeg是一个C语言库,天生具备跨平台能力,所以学习的话笔者倡议间接在PC上实际学习即可,如果你都学会了,那移植到其余平台那不是so easy吗。 明天笔者应用的是命令行装置的形式集成FFmpeg,在Mac上咱们能够应用Homebrew包管理工具进行装置,Linux上能够用apt。 1、首先应用Homebrew装置ffmpeg: brew install ffmpeg而后静静期待即可,个别如果失败的话多是网络问题吧,解决形式家喻户晓... 2、装置胜利后咱们用brew info命令查看一下装置到哪里去了,前面引入工程时须要用到,命令是: brew info ffmpeg例如笔者的输入如图: 配置CLion工程新建好CLion工程后,咱们将FFmpeg的库门路和头文件配置一下,配置CMakeLists.txt: cmake_minimum_required(VERSION 3.17)# 留神 FFmpegPro是工程名称,开发这须要依照理论进行替换project(FFmpegPro)set(CMAKE_CXX_STANDARD 11)# FFmpeg的装置目录,能够通过命令"brew info ffmpeg"获取set(FFMPEG_DIR /opt/homebrew/Cellar/ffmpeg/5.0)# 头文件搜寻门路include_directories(${FFMPEG_DIR}/include/)# 动态链接库或动态链接库的搜寻门路link_directories(${FFMPEG_DIR}/lib/)add_executable(FFmpegPro main.cpp)#链接库target_link_libraries(FFmpegPro #FFmpeg 库 avcodec avfilter avformat avutil swresample swscale )简略测试一下配置是否胜利,在main代码中简略调用一些ffmpeg库的API,如果能失常运行则示意配置胜利: #include <iostream>extern "C"{#include "libavcodec/avcodec.h"#include <libavformat/avformat.h>#include "libavutil/avutil.h"}int main(int arg,char **argv) { // 打印ffmpeg的信息 std::cout << "av_version_info:" << av_version_info() << std::endl; std::cout << "av_version_info:" << avcodec_configuration() << std::endl; return 0;}运行如果能失常打印出ffmpeg的版本号即示意环境配置胜利。 ...

October 12, 2022 · 1 min · jiezi

关于c++:c-primer-练习633递归函数使用迭代器踩坑记录

练习6.33:编写一个递归函数,输入vector对象的内容 问题复现如题,笔者在实现练习6.33时,依据题意写出的代码如下 void myPrint(vector<int> v,vector<int>::iterator it) { if (it != v.end()) { cout << *it; myPrint(v, it++); }}int main() { vector<int> v = { 1,2,3,4 }; myPrint(v,v.begin()); return 0;}试图在递归中应用迭代器,一运行发现报错,报错提醒:vector的迭代器不兼容 起因:后百度查阅知,myVector传入的是一般形参,运行时会先将实参v拷贝一份,拷贝之后的不是原来的v的迭代器了,这时再与原来的v.end()作比拟就提醒迭代器不兼容了 解决办法:将形参v改为援用,这时迭代器就都是同一个v下的,不呈现不兼容景象

October 12, 2022 · 1 min · jiezi

关于c++:技术解读现代化工具链在大规模-C-项目中的运用-龙蜥技术

编者按:C++ 语言与编译器始终都在继续演进,呈现了许多令人振奋的新个性,同时还有许多新个性在孵化阶。除此之外,还有许多小更改以进步运行效率与编程效率。本文整顿自寰球 C++ 及系统软件技术大会上的精彩分享,接下来由作者带咱们理解 C++ 我的项目的实际工作等具体内容,全文整顿如下: 介绍C++ 是一门有着短暂历史并仍然继续沉闷的语言。C++ 最新规范曾经到了 C++23。Clang/LLVM、GCC 与 MSVC 等三大编译器都放弃着十分频繁的更新。除此之外的各个相干生态也都放弃着继续更新与跟进。但遗憾的是,目前看到踊跃更近 C++新规范与 C++新工具链的都次要以国外我的项目为主。国内尽管对 C++ 新规范也十分关注,但大多以爱好者集体为主,不足实在我的项目的跟进与实际。 本文以现代化工具链作为线索,介绍咱们理论工作中的大型 C++ 我的项目中现代化工具链的实际以及后果。 对于 C++ 我的项目,特地是大型的 C++我的项目而言,经常会有以下几个特点(或痛点): 我的项目高度自治 – 自主决定编译器版本、语言规范高度业务导向 – 少关注、不关注编译器和语言规范先发劣势 – 丢失利用新技术、新个性的能力沉疴难起 – 编译器版本、语言规范、库依赖被锁死许多 C++ 我的项目都是高度自治且业务导向的,这导致一个公司外部的 C++ 我的项目的编译器版本和语言规范形形色色,想对立十分艰难。同时因为日常开发次要更关怀业务,工夫一长背上了技术债,再想用新规范与新工具链的老本就更高了。一来二去,编译器、语言规范与库依赖就被锁死了。 同时对于业务来说,切换编译器也会有很多问题与挑战: 修复更严格编译器查看的问题修复不同编译器行为差别的问题修复语言规范、编译器行为扭转的问题 – 欠缺测试二进制依赖、ABI兼容问题 – 全源码编译/服务化性能压测、调优这里的许多问题哪怕对于有许多年教训的 C++工程师而言可能都算是难题,因为这些问题其实实质上是比语言层更低一层的问题,属于工具链级别的问题。所以大家感觉辣手是很失常的,这个时候就须要业余的编译器团队了。 在咱们的工作中,多数编译器造成的程序行为变动问题须要欠缺的测试集,极少数编译器切换造成的问题在产线上裸露进去 – 实质是业务/库代码的 bug,绝大多数问题在构建、运行、压测阶段裸露并失去修复。 这里咱们简略介绍下咱们在理论工作中遇到的案例: 业务1(规模5M) 业务自身10+仓库;三方依赖50+,其中大部分源代码依赖,局部二进制依赖。二进制依赖、ABI兼容问题 – 0.5人月;编译器切换、CI、CD – 1.5人月;性能剖析调优 – 1人月。业务2(规模7M) 二方/三方依赖 30+,二进制依赖。编译器切换革新 – 2 人月;性能压测调优 – 1 人月。业务3(规模3M) 二方/三方依赖 100+,多为二进制依赖。二进制依赖、ABI 兼容问题 – 预估 2 人年。在切换工具链之后,用户们能失去什么呢? ...

October 11, 2022 · 3 min · jiezi

关于c++:C20协程学习

导语 | 本文推选自腾讯云开发者社区-【技思广益 · 腾讯技术人原创集】专栏。该专栏是腾讯云开发者社区为腾讯技术人与宽泛开发者打造的分享交换窗口。栏目邀约腾讯技术人分享原创的技术积淀,与宽泛开发者互启迪共成长。本文作者是腾讯后盾开发工程师杨良聪。 协程(coroutine)是在执行过程中能够被挂起,在后续能够被复原执行的函数。在C++20中,当一个函数外部呈现了co_await、co_yield、co_return中的任何一个时,这个函数就是一个协程。 C++20协程的一个简略的示例代码: coro_ret<int> number_generator(int begin, int count) {    std::cout << "number_generator invoked." << std::endl;    for (int i=begin; i<count; ++i) {        co_yield i;    }    co_return;}int main(int argc, char* argv[]){    auto g = number_generator(1, 10);    std::cout << "begin to run!" << std::endl;    while(!g.resume()) {        std::cout << "got number:" << g.get() << std::endl;    }    std::cout << "coroutine done, return value:" << g.get() << std::endl;    return 0;}number_generator内呈现了co_yield和co_return所以这不是一个一般的函数,而是一个协程,每当程序执行到第4行co_yield i;时,协程就会挂起,程序的控制权会回到调用者那里,直到调用者调用resume办法,此时会复原到上次协程yield的中央,持续开始执行。 ...

October 8, 2022 · 3 min · jiezi

关于c++:Folly库代码赏析8IO

IOBufIOBuf相似于linux中的sk_buf,是一个网络编程中的常见概念,用一个物理上的非间断空间虚构出逻辑上的间断空间,同时利用援用计数防止拷贝复制。 空间布局如右所示:headRoom + data + tailRoom,因而能够prepend() && append()。 同时通过多个IOBuf chain连接成逻辑上的间断空间,通过unlink开释。 同时兼容了iovec调用,充分利用多个小块读写。 EventBase基于IOBuf和RequestCtx,引入了和libevent相似的事件循环模型。 教训为了P99,肯定要把CPU密集事件挪动到专门的CPU密集操作池中,避免拖慢IO事件。

October 4, 2022 · 1 min · jiezi

关于c++:Folly库代码赏析7Executor

Folly 的余下内容分为 [ ] synchronization[ ] memory[ ] logging[ ] io[ ] gen[ ] fibers[ ] executors[ ] concurrencyclassDiagram Executor Executor <|-- IOExecutor Executor <|-- ThreadPoolExecutor IOExecutor <|-- IOThreadPoolExecutor ThreadPoolExecutor <|-- IOThreadPoolExecutor ThreadPoolExecutor <|-- CPUThreadPoolExecutor Executor <|-- DrivableExecutor Executor <|-- ManualExecutorExecutorKeepAlive是对Executor的平安援用,Executor析构时会join所有KeepAlive对象。 ThreadExecutor对于每个task启动一个线程执行,通过channel告诉工作增加、删除、完结。golang中的select channel 用法。 ThreadPoolExecutorIO/CPUThreadPoolExecutor的基类,提供了统计性能等通用信息。 IOThreadPoolExecutor提供多个ioThread,每个ioThread容许event_base loop。

October 3, 2022 · 1 min · jiezi

关于c++:C模板元编程实战读书笔记

C++模板元编程是函数式编程,是无副作用的函数(输出雷同,屡次调用输入雷同)。constexpr就是标注这个函数无副作用(数值元函数),与之对应的是类型元函数。类型元函数:输出参数为类型,输入参数也为类型。template <>struct Fun<int>{ using reference_type = int&; using value_type = int;};输出为int,输入为Fun<int>::reference_type/value_type 当constexpr函数传入constexpr参数时,则进行编译期计算,否则进行运行时计算。元数据分为 数值类型模板容器模板:通过可变参数模板作为元数据的容器,另外只在必要时才进行定义。程序、条件分支、循环语句 程序条件分支 std::conditional_t偏特化(留神未齐全特化的类中不容许有齐全特化)std::enable_if_t 当条件为真时返回type,利用了SFINAE,匹配失败并非谬误循环:应用递归运算循环,偏特化作为完结的条件。编译器分支和运行时函数相结合,通过元函数在编译期抉择正确的运行时函数。利用if constexpr抉择运行时执行的代码。CRTP

October 3, 2022 · 1 min · jiezi

关于c++:Folly库代码赏析5FuturePromise模型

前言通常来说,有两种异步模式,一种是基于goroutine的用户态协程并发模型,另一种是基于Future/Promise的并发模型。后者可能将多个Future串联,改善回调天堂这一状况。其实Javascript早就提供了Promise模型,异步基于事件循环来做,每次都是将异步事件插入工夫序列期待下一次调用。而像C++/Rust这些语言就必须通过额定的executor库就安顿异步事件的执行。Rust中曾经有了十分优良的异步运行时tokio,Folly的实现该当是差不多的。 对Folly的介绍基于自底向上进行的办法,从底层building block到下层高级原语。 CoreKeepAlive and DeferredKeepAlive是对executor的平安援用,保障不会在KeepAlive存活时析构executor。 Deferred是尚未设置理论executor的代理,后续须要注入指定的executor。 Info flowCore保护三种info flow producer => consumer:result、callback、executor、priorityconsumer => producer:interrupt 、interrupt handler 相似于Linux中的信号,用于勾销或xxcallback的执行lifetime control: 2 ref counts(attached_ 和 callbackref_),管制析构上面是一张 producer => consumer 的状态转换图,清晰地转换Core的各种状态以及触发条件。 /// +----------------------------------------------------------------+/// | ---> OnlyResult ----- |/// | / \ |/// | (setResult()) (setCallback()) |/// | / \ |/// | Start ---------> ------> Done |/// | \ \ / |/// | \ (setCallback()) (setResult()) |/// | \ \ / |/// | \ ---> OnlyCallback --- |/// | \ or OnlyCallbackAllowInline |/// | \ \ |/// | (setProxy()) (setProxy()) |/// | \ \ |/// | \ ------> Empty |/// | \ / |/// | \ (setCallback()) |/// | \ / |/// | --------> Proxy ---------- |/// +----------------------------------------------------------------+模块设计Core分为CoreBase 和Core<T>,将与模板无关的信息集中在Core<T>中。 ...

October 2, 2022 · 1 min · jiezi

关于c++:Folly库代码赏析4BenchMark

BenchMark框架基于这样一种思维:测量时候肯定有噪声的存在,导致咱们的测量值偏大。因而不应该对多组测量后果求均匀,而是应该求最小值。 第一个乏味的中央是如何确保一个无用的表达式求值,Folly中是利用了句号表达式 + 匿名变量#define BENCHMARK_IMPL(funName, stringName, rv, paramType, paramName) \ static void funName(paramType); \ FOLLY_MAYBE_UNUSED static bool FB_ANONYMOUS_VARIABLE(follyBenchmarkUnused) = \ (::folly::addBenchmark( \ __FILE__, \ stringName, \ [](paramType paramName) -> unsigned { \ funName(paramName); \ return rv; \ }), \ true); \ static void funName(paramType paramName)宏开展之后,就实现了函数的申明和并将测试函数注入框架。 第二个有意思的中央是如何保障一个变量的申明周期在整个代码块内,即咱们心愿BENCHMARK_SUSPEND { v.reserve(n);}BENCHMARK_SUSPEND是通过管制对应变量的生命周期管制计时流程的,因而,咱们心愿在这个宏中结构的变量的生命周期贯通整个代码块。 #define BENCHMARK_SUSPEND \ if (auto FB_ANONYMOUS_VARIABLE(BENCHMARK_SUSPEND) = \ ::folly::BenchmarkSuspender()) { \ } else十分奇妙的利用了在if中申明的变量的scope在else之后完结的冷常识 ref:

October 1, 2022 · 1 min · jiezi

关于c++:排序算法

源码地址(gitee)堆排序源码地址:https://gitee.com/BJFyfwl/Lin...其余排序办法源码地址:https://gitee.com/BJFyfwl/Lin...常见排序算法插入排序: 间接插入排序希尔排序抉择排序: 间接抉择排序堆排序替换排序: 冒泡排序疾速排序归并排序间接插入排序核心思想:将一个数插入一段有序区间。希尔排序核心思想: 先分组预排序(应用间接插入排序),使整个数组靠近有序(小的数在前,大的数在后)再间接插入排序能够将较大的数疾速地挪动到前面,实用于大量数据gap == 1就相当于间接插入排序。gap越大,预排越快,预排序越不靠近有序。gap越小,预排越慢,预排序越靠近有序。间接抉择排序遍历数组,选出最大的数,与最初一个数替换。而后顺次遍历抉择次大的数,与倒数第二个数替换。如此循环。堆排序建堆工夫是O(N)排序工夫是O(logN)堆只存在两种类型:大根堆和小根堆。大根堆:根节点是最大的(即孩子节点 < 父亲节点)小根对:根节点是最小的(即孩子节点 > 父亲节点)堆在逻辑构造上是齐全二叉树,在物理构造上还是数组模式。所以实现堆时,依然以数组来存储。堆的下标法则设父节点下标为 x,右边子节点下标为 y,左边节点下标为 z。y = x*2 + 1;z = x*2 + 2;x = (x - 1)/ 2 或者 (y-1)/ 2;堆排序问题一:假如数组数据很大(有10亿个数,大略4G内存),他们存在文件中,取最大的前k个数解决办法:建设一个 k 个数的小根堆,而后将文件中的数顺次取出与根节点比拟,如果比根节点大,则替换根节点,而后向下调整,如此循环,最初这个小根堆中的数据就是最大的前k个数。堆排序问题二:堆排序:将一个数组升序排列解决办法:将数组建设小根堆,顺次取根节点的数据,而后将根节点数据与开端数据交换,再删除开端数据(即删除最小的那个数了),而后再向下调整,如此循环即可。疾速排序工夫复杂度 O(N * logN)空间复杂度O(logN)稳定性:不稳固如何取要害数key先取数组的第一个数、最初一个数和两头地位的数,而后取这三个数中不是最大也不是最小的那个数作为key。这种办法能够防止key间接选到最大值或者最小值。左右指针法快排 一前一后两个指针,抉择一个要害数key(个别是结尾位或者末位)如果抉择结尾位为要害数key,则让end向后先走,寻找比key小的数,找到小的数后停下。而后pre向前走,寻找比key大的数,找到后进行。而后替换pre的值和end的值,替换完后,end持续向后挪动。始终循环,直到pre和end相遇为止,相遇时的值肯定是比key小的,所以替换key和pre的值这样,key的数就会被挪动到整个数组的两头值地位,它右边的都比它小,左边的都比它大最初应用递归。挖坑法快排 另外定义一个变量sum,用来保留第一个pre,pre的地位则空进去了。而后end先向前挪动,寻找比sum小的数,找到后将end与pre替换,当初end的地位为空。而后pre向前挪动,寻找比sum大的数,找到将pre与end替换,当初pre的地位为空。而后再是end向前挪动………………这样循环直到pre和end相遇为止,相遇时的地位为空,再将sum的值放到相遇的地位上。这样这个数的右边都是比它小的数,左边都是比它大的数。最初应用递归即可。前后指针法快排 起始地位,pre在第一位,end在第二位。而后end向后挪动,寻找比key小的值,找到后,pre++,而后替换pre和end的值。而后持续end向后挪动,直到end拜访完为止最初在替换pre和key的值这样key这个数的右边都是比它小的数,左边都是比它大的数。最初递归即可。递归式快排的小区间优化当数据量很大时,在最初几层递归时,会呈现大量递归(呈现大量递归时可能会栈溢出),然而每个递归解决的数据较小。所以为了防止最初几层的递归,在数据量较小时,间接应用插入排序这样大数据处理的最初几层递归,则变为插入排序,能够缩小大量递归,升高解决工夫。非递归快排应用循环代替递归。为了防止栈溢出,本人创立一个栈(malloc创立的空间是在堆中的),应用循环来进行排序,其实质是本人模仿栈的出栈和压栈。而后将单趟排序隔离进去,压栈时将pre和end的下标压栈,出栈将pre和end传给单趟排序,并且将栈中的pre和end打消,循环如此即可排序。计数排序外围思路:依据所给数组的最大值与小值,开拓等大小的数组,并且初始化为0,遍历数组,将该整数对应下标的新数组的地位加1。(相当于一种映射)例如:给定一个数组 {5,6,7,8,9,6}最大值为9,最小值为5,开拓新数组 arr 大小为 5。遍历数组,第一个数为 5 ,对应下标为 0,即arr[0]++,如此遍历残缺个数组即可。适用范围只适宜数据范畴比拟集中的数组,如果数据集中效率还是很高的。并且只适宜整数,浮点数和字符串等都不适宜。归并排序核心思想:将数组切分成两份,如果右边有序,左边也有序,那么两份归并,整个数组都是有序的了。归并的海量数据处理(外排序)例如:一个4G的文件,文件中是一些整数,将这些整数排序,零碎提供内存为512M 将文件分成 8 等分,而后别离将小文件的数据读取到内存中进行排序(不要用归并,因为归并有O(N)的空间复杂度)这样 8 份小文件中的数据都是有序的了。而后再将 8 分小文件两两进行归并,合称 4 份有序文件而后再归并,最初归并成一个有序的大文件。算法复杂度及稳定性数组中雷同的值,排完序后绝对地位不变,就是稳固的,否则就是不稳固。

September 30, 2022 · 1 min · jiezi

关于c++:Folly库代码赏析3AtomicUnorderedMap

AtomicUnorderedMap是一个不反对删除、反对高并发读写、反对自定义K、V的哈希表,只反对一个findOrConstruct操作。 template <typename Func> std::pair<const_iterator, bool> findOrConstruct(const Key& key, Func&& func) { // 依据哈希算法定位到索引 auto const slot = keyToSlotIdx(key); auto prev = slots_[slot].headAndState_.load(std::memory_order_acquire); // 遍历动态链表查找键是否存在 auto existing = find(key, slot); if (existing != 0) { return std::make_pair(ConstIterator(*this, existing), false); } // 在左近找一个空slot,同时设标记位为CONSTRUCTING auto idx = allocateNear(slot); new (&slots_[idx].keyValue().first) Key(key); func(static_cast<void*>(&slots_[idx].keyValue().second)); while (true) { slots_[idx].next_ = prev >> 2; // we can merge the head update and the CONSTRUCTING -> LINKED update // into a single CAS if slot == idx (which should happen often) auto after = idx << 2; // 第一次就查找到空slot if (slot == idx) { after += LINKED; } else { after += (prev & 3); } // 没有其他人读写原始slot prev if (slots_[slot].headAndState_.compare_exchange_strong(prev, after)) { // success if (idx != slot) { slots_[idx].stateUpdate(CONSTRUCTING, LINKED); } return std::make_pair(ConstIterator(*this, idx), true); } // compare_exchange_strong updates its first arg on failure, so // there is no need to reread prev // 原来的slot有变动,看看是不是其余线程进行了插入 existing = find(key, slot); if (existing != 0) { // our allocated key and value are no longer needed slots_[idx].keyValue().first.~Key(); slots_[idx].keyValue().second.~Value(); slots_[idx].stateUpdate(CONSTRUCTING, EMPTY); return std::make_pair(ConstIterator(*this, existing), false); } } }

September 30, 2022 · 1 min · jiezi

关于c++:Folly库代码赏析1AtomicHashArray

Folly是facebook公司提供的开源C++代码库,品质很高,用以补充规范库和boost库的有余,在性能方面提出了很高的要求。 AtomicHashArray是用于构建AtomicHashMap的原料,在某些条件下面做了额定要求,通过升高通用性达到进步特定条件下性能的目标。 当通过AtomicHashArray::Config构建时,因为static initialization order fiasco,咱们只能通过提供默认函数参数而不是提供一个动态全局实例。 实质上,AtomicHashArray就是一个动态数组,通过CAS操作实现并发插入、删除操作。关键在于如何封装使得对元素操作原子化。 提供了三个标记元素 empty_key、locked_key、erased_key。 插入时:通过原子性的变更key,例如讲empty_key变更为locked_key,从而实现单个元素的上锁,而后再进行value的结构,最初set new_key。当然,这里对key的限度比拟大,要求key可能convert to int32。 删除时:定位到给定元素,而后CAS更改为erased_key即可实现删除操作,只是打了一个墓碑标记,不适宜删除很多元素时应用。 同样的,哈希抵触基于凋谢地址法解决。通过模板提供了线性探测和平方探测两种策略。 迭代器遍历元素时也要越过相应的墓碑和空位。

September 30, 2022 · 1 min · jiezi

关于c++:Folly库代码赏析2AtomicHashMap

AtomicHashArray中通过将key强制转型为std::atomic<KeyT>*来实现key的原子操作。为了防止低廉操作,如通过stringpiece查找string,AtomicHashMap提供了转换函数容许提供可转换位key的查问参数,即便不是同一类型,也能够比拟二者是否相等。AtomicHashMap的插入操作: 向primary AtomicHashArray中插入如果已满,调配sub map并插入底层调配策略: // if subMap == 0 (primary map) =>// bit(s) value// 31 0// 0-30 submap offset (index_ret input)//// if subMap > 0 (secondary maps) =>// bit(s) value// 31 1// 27-30 which subMap// 0-26 subMap offset (index_ret input)底层调配是1个primary map + N个sub map。 总和容量实际上是和2个primary map统一的,为了防止内存节约,通过溢出时再调配多个sub map去防止不必要的内存节约。

September 30, 2022 · 1 min · jiezi

关于c++:红黑树

红黑树概念 红黑树是一种二叉搜寻树,在每个节点上减少一个存储位,用来存储节点色彩(红或黑)通过对通过对色彩的限度,确保任意一条从根节点到叶子节点的门路不会比其余门路长出两倍(即最长门路最多只能是最短门路的两倍)红黑树通过对色彩的管制,从而达到近似均衡(AVL是严格均衡的)AVL树通过旋转形式来管制均衡,而其搜寻效率上跟红黑树差不多(红黑树效率要略低)尽管红黑树效率略低,然而AVL树旋转次数过多,综合来说红黑树更好一些。红黑树性质每个节点只能是红色或者彩色。根节点是彩色。如果一个节点是红色,那么它的两个子节点就是彩色(如果一个节点是彩色,那么它的子节点能够是红色也能够是彩色)(即不存在间断的红色节点)对于每个节点,从该节点到其后辈的所有叶子节点的门路上,每条门路的彩色节点数雷同(包含最初的空节点)所有的空节点都是彩色。通过上述规定的管制,就能够保障红黑树的最长门路中节点个数不会超过最短门路节点数的两倍。最长门路一黑一红,最短门路全黑。红黑树节点定义形式个别在插入新节点时,默认插入节点色彩为红色,因为默认为彩色节点,肯定会毁坏规定四,影响较大,然而默认为红色节点,只是有可能毁坏规定三。template<class K,class V>struct RBTreeNode{ RBTreeNode<K, V>* _left; RBTreeNode<K, V>* _right; RBTreeNode<K, V>* _parent; pair<K, V> _kv; //键值对,存储数据 Colour _col; //存储色彩 RBTreeNode(const pair<K, V>& kv) :_left(nullptr) , _right(nullptr) , _parent(nullptr) , _kv(kv) , _col(RED) //默认节点色彩为红色 { }};红黑树新增节点的三种状况cur为新增节点,p 为父节点,g为祖父节点,u为叔叔节点(要害看叔叔节点的色彩)蓝色方框为红黑子树。状况一:cur为红(在p的左右皆可),p为红,g为黑,u存在且为红解决办法:变色将父节点和叔叔节点都变为黑,并且将祖父节点变为红如果祖父节点的父节点也为红,违反规定三,则持续向上进行变换。如果祖父节点为根节点,违反规定二,则再将祖父节点变为黑。状况二:cur为红,且在p的右边,p为红,g为黑,u不存在或者存在且为黑cur在父节点的右边。解决办法:单右旋+变色(祖孙三代是直线关系)进行右单旋转将父节点变为黑,祖父节点变为红。状况三:cur为红,且在p的左边,p为红,g为黑,u不存在或者存在且为黑解决办法:双旋转+变色(祖孙三代是折线关系)先进行左单旋,再进行右单旋,最初再变色。源码地址gitee:https://gitee.com/BJFyfwl/Lin...

September 29, 2022 · 1 min · jiezi

关于c++:项目篇高并发内存池

根底概念池化技术所谓池化技术,就是程序先向零碎申请适量的资源,而后本人治理,当程序中须要申请内存时,不是间接向操作系统申请,而是间接从内存池中获取,开释内存时也不是将内存返回给操作系统,而是返回内存池中。因为每次申请该资源都有较大的开销,这样提前申请好了,应用时就会十分快捷,可能大大提高程序运行效率。在计算机中有很多应用这种池技术的中央,例如线程池、连接池等。动态内存申请mallocC++中动静申请内存都是通过malloc去申请的,但实际上咱们并不是间接去堆中获取内存的,而malloc就是一个内存池。malloc() 相当于向零碎 “零售” 了一块较大的内存空间,而后“批发” 给程序应用,当全副应用完或者程序有大量内存需要时,再依据需要向操作系统申请内存。定长内存池设计设计思路开拓内存: 应用malloc开拓一大块内存,让_memory指针指向这个大块内存_memory 设置为char* 类型,是为了不便切割时_memory向后挪动多少字节数。申请内存: 将_memory强转为对应类型,而后赋值给对方,_memory指针向后挪动对应字节数即可。如果有存在曾经切割好的小块内存,则优先应用小块内存。开释内存: 用类型链表的构造来进行存储。用以后小块内存的头4字节存储下一个小块内存的地址,最初用_freeList指针指向第一个小块内存的地址(并不是将内存开释给操作系统)所以开拓内存时,开拓的内存大小必须大于或等于一个指针类型的大小。代码地位:高并发内存池我的项目中的ObjectPool.h 文件。高并发内存池整体设计框架三层设计思路第一层:thread cache(线程缓存): 每个线程独享一个thread cache,用于小于256k的内存分配情况,线程从这里申请内存不须要加锁(因为其余线程无法访问以后线程的 thread cache,没有竞争关系)第二层:central cache(核心缓存): 所有线程共享一个central cache,thread cache 是按需从central cache中获取对象,central cache在适合的时候会发出thread cache中的对象,防止一个线程占用太多资源。central cache 是所有线程共享的,所以存在竞争关系,须要加锁;这里应用的锁是桶锁,并且因为只有thread cache没有内存时才会申请内存,所以这里竞争不会太强烈。第三层:page cache(页缓存): 页缓存存储的内存是以页为单位进行存储的及调配的。central cache没有内存时,则会从page cache中申请肯定数量的page,并切割成定长大小的小内存块。当一个span的几个跨度页的对象都回收后,page cache会回收central cache满足条件的span对象,并且合并相邻的页,组成更大的页,缓解内存碎片的问题。 thread cache 设计思路(线程缓存)线程申请内存: 线程申请内存时,会有不同规格的内存申请(4字节、5字节等),依据范畴划定不同的自在链表,设计多个自在链表治理不同规格的内存小块。本质就相当于应用多个定长内存池的自在链表每个内存小块采纳向上对齐准则(可能会呈现多申请内存的状况,这就是内碎片)例如: 须要9字节,则开拓一个大小为2个8字节的空间的节点须要100字节,则开拓一个大小为13个8字节的空间的节点。线程对齐规定: 整体管制在最多10%左右的内碎片节约总计设计208个桶[0,15]个桶,每个桶的对齐数相差8字节(最高128字节对齐)[16,71]个桶,每个桶的对齐数相差16字节(最高1024字节对齐)以此类推 留神:_freeLists是一个数组,每个元素都是自在链表类型(即存储自在链表的头结点)线程开释内存 开释内存后:采纳自在链表的构造来治理切好的小块内存(每一个切分好的小块内存就是一个节点)具体方法是:用切分好的小块内存的前4字节或8字节来存储下一个小块内存的地址。插入节点时,采纳头插的形式。线程缓存无锁设计(TLS)TLS:thread local storage 线程本地存储(linux和Windows下有各自的TLS)TLS是一种变量的存储形式,这个变量在它所在的线程内是全局可拜访的,然而不能被其余线程拜访,这样就保障了线程的独立性。动态TLS应用办法: _declspec(thread) DWORD data=0;申明了一个 _declspec(thread) 类型的变量,会为每一个线程创立一个独自的拷贝。原理: 在x86 CPU上,将为每次援用的动态TLS变量生成3个辅助机器指令如果在过程中创立子线程,那么零碎将会捕捉它并且主动调配一另一个内存块,以便寄存新线程的动态TLS变量。//每个线程刚创立时,就会取得这个指针,每个线程的指针是不同的。static _declspec(thread) ThreadCache* pTLSThreadCache = nullptr;//static 润饰,能够保障变量只在以后文件可见。central cache设计思路(核心缓存)central cache也是一个哈希桶构造,每个哈希桶地位挂载的是SpanList自在链表构造。Span治理的是以页为单位的大块内存(一页为8kb(32位零碎下))每个Span中的大内存依据映射关系被切成了一个个的小块内存对象,而后挂载在Span上。因为核心缓存是所有线程共享的,只须要定义一个对象,所以这里须要将 central cache 设计为单例模式(这里采纳饿汉模式的设计办法)留神: span是双向链表,而span下挂载的小块内存对象是单链表。核心缓存须要加桶锁。_spanLists 是一个数组,数组中每个元素都是一个span自在链表的_head头指针。每个span又是一个单向自在链表。 内存申请 当thread cache中没有内存时,就会批量向central cache申请一些内存对象,从对应的span中取出小块内存对象给thread cache,这个过程是须要加锁的(加桶锁)这里批量获取对象的数量应用了相似网络tcp协定拥塞管制的慢开始算法。如果所有的span都为空了(即central cache应用完了),则将空的span链在一起,向page cache申请一个span对象,span对象中是一些以页为单位的内存,须要切成对应的小块内存对象,并链接起来,挂到span中。central cache中每一个span都有一个use_count,调配一个对象给thread cache,就加加。内存开释: ...

September 28, 2022 · 1 min · jiezi

关于c++:百度工程师带你探秘C内存管理理论篇

作者 | daydreamer 在互联网的服务中,C++罕用于搭建高性能、高并发、大流量、低延时的后端服务。如何正当的分配内存满足零碎高性能需要是一个高频且重要的话题,而且因为内存本身的特点和理论问题的简单,组合出了诸多难题。 咱们能够对内存进行多种类型的划分,从内存申请大小来看: 小对象调配:小于4倍内存页大小的内存调配,在4KiB页大小状况下,<16KiB算作小对象调配;大对象调配:大于等于4倍内存页大小的内存调配,在4KiB页大小状况下,>=16KiB算作大对象调配。从一块内存的被持有时长来看: 后端一次申请内甚至更短时间申请和开释任意工夫窗口内内存持有和更新简直与利用过程等长的内存持有和更新某个过程沦亡后一段时间内,由该过程申请的仍具备意义的内存持有和开释当然还能够依照内存申请开释频率、读写频率进行进一步的分类。 内存治理服务于利用零碎,目标是帮助零碎更好的解决瓶颈问题,比方对于『如何升高后端响应的提早和进步稳定性』内存治理可能要思考的是: 解决内存读写并发(读频繁or写频繁)升高响应工夫和CPU耗费应用层的内存的池化复用底层内存向零碎申请的内存块大小及内存碎片化每一个问题开展可能都是一个比拟大的话题,本文作为系列文章《探秘C++内存治理》的开篇,先介绍Linux C++程序内存治理的实践根底。后续会持续解密C++程序罕用的内存治理库的实现原理,包含ptmalloc,jemalloc,tcmalloc等,介绍以后业界风行的内存分配器如何治理C++程序的内存。理解内存分配器原理,更有助于工程师在实践中升高解决内存应用问题的老本,依据零碎量身打造应用层的内存管理体系。 一、Linux内存治理Linux自底向上大抵能够被划分为: 硬件(Physical Hardware)内核层(Kernel Space)用户层(User Space) △图1:Linux构造 内核模块在内核空间中运行,应用程序在用户空间中运行,二者的内存地址空间不重叠。这种办法确保在用户空间中运行的应用程序具备统一的硬件视图,而与硬件平台无关。用户空间通过应用零碎调用以可控的形式使内核服务,如:陷入内核态,解决缺页中断。 Linux的内存管理系统自底向上大抵能够被划分为: 内核层内存治理 : 在 Linux 内核中 , 通过内存调配函数治理内存:kmalloc()/\_\_get\_free\_pages():申请较小内存(kmalloc()以字节为单位,\_\_get\_free\_pages()以一页128K为单位),申请的内存位于物理内存的映射区域,而且在物理上也是间断的,它们与实在的物理地址只有一个固定的偏移。vmalloc():申请较大内存,虚拟内存空间给出一块间断的内存区,但不保障物理内存间断,开销远大于\_\_get\_free\_pages(),须要建设新的页表。用户层内存治理:通过调用零碎调用函数(brk、mmap等),实现罕用的内存治理接口(malloc, free, realloc, calloc)治理内存;经典内存治理库ptmalloc2、tcmalloc、jemalloc。应用程序通过内存治理库或间接调用零碎内存治理函数分配内存,依据应用程序自身的程序个性进行应用,如:单个变量内存申请和开释、内存池化复用等。至此单个过程能够应用Linux提供的内存划分顺利的运行,从用户程序来看Linux过程的内存模型大抵如下所示: △图2:Linux过程的内存模型 栈区(Stack):存储程序执行期间的本地变量和函数的参数,从高地址向低地址成长堆区(Heap): 动态内存调配区域,通过malloc、new、free和delete等函数治理在规范C库中,提供了malloc/free函数调配开释内存,这些函数的底层是基于brk/mmap这些零碎调用实现的,对照图2来看: brk(): 用于申请和开释小内存。数据段的开端,堆内存的开始,叫做brk(program break)。通过设置heap的完结地址,将该地址向高或低挪动实现堆内存的扩张或膨胀。低地址内存必须在高地址内存的开释之后能力失去的开释,被标记为闲暇区的低地址,无奈被合并,如果后续再来内存空间的申请大于此闲暇区,这部分将成为内存空洞。默认状况下,当最高地址空间的闲暇内存超过128K(可由M\_TRIM\_THRESHOLD选项调节)时,执行内存压缩操作(trim)。mmap():用于申请大内存。mmap(memory map)是一种内存映射文件的办法,行将一个文件或者其它对象映射到过程的虚拟地址空间中(堆和栈两头的文件映射区域 Memory Mapping Segment),实现文件磁盘地址和过程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,过程就能够采纳指针的形式读写操作这一段内存,而零碎会主动回写脏页面到对应的文件磁盘上,内核空间对这段区域的批改也间接反映用户空间,从而能够实现不同过程间的文件共享。大于 128 K 的内存,应用零碎调用mmap()分配内存。与 brk() 分配内存不同的是,mmap() 调配的内存能够独自开释。munmp():开释有mmap()创立的这段内存空间。但在对于多个同时运行的过程,零碎仍需解决无限的物理内存和增长的内存地址等问题。那么当Linux存在多个同时运行的过程时,一次内存的调配过程具体都通过哪些过程呢?古代Linux零碎上内存的调配次要过程如下[1] : 应用程序通过调用内存调配函数,零碎调用brk或者mmap进行内存调配,申请虚拟内存地址空间。虚拟内存至物理内存映射处理过程,通过申请MMU调配单元,依据虚拟地址计算出该地址所属的页面,再依据页面映射表的起始地址计算出该页面映射表(PageTable)项所在的物理地址,依据物理地址在高速缓存的TLB中寻找该表项的内容,如果该表项不在TLB中,就从内存将其内容装载到TLB中。 △图3:Linux内存分配机制(虚构+物理映射) 对于内存调配过程中波及到工具进一步分析: 虚拟内存(Virtual Memory):古代操作系统广泛应用的一种技术,每个过程有用独立的逻辑地址空间,内存被分为大小相等的多个块,称为页(Page)。每个页都是一段间断的地址,对应物理内存上的一块称为页框,通常页和页框大小相等。虚拟内存使得多个虚构页面共享同一个物理页面,而内核和用户过程、不同用户过程隔离。MMU(Memory-Management Unit):内存治理单元,负责管理虚拟地址到物理地址的内存映射,实现各个用户过程都领有本人的独立的地址空间,提供硬件机制的内存拜访权限查看,爱护每个过程所用的内存不会被其余的过程所毁坏。PageTable:虚拟内存至物理内存页面映射关系存储单元。TLB(Translation Lookaside Buffer):高速虚构地址映射缓存, 次要为了晋升MMU地址映射解决效率,加了缓存机制,如果存在即可间接取出映射地址供应用。这里要提到一个很重要的概念,内存的提早调配,只有在真正拜访一个地址的时候才建设这个地址的物理映射,这是 Linux 内存治理的根本思维之一。Linux 内核在用户申请内存的时候,只是调配了虚拟内存,并没有调配理论物理内存;当用户第一次应用这块内存的时候,内核会产生缺页中断,调配物理内存,建设虚拟内存和物理内存之间的映射关系。当一个过程产生缺页中断的时候,过程会陷入内核态,执行以下操作: 查看要拜访的虚拟地址是否非法查找/调配一个物理页填充物理页内容建设映射关系(虚拟地址到物理地址)从新执行触发缺页中断的指令如果填充物理页的过程须要读取磁盘,那这次缺页中断是majflt,否则是minflt。咱们须要重点关注majflt的值,因为majflt对于性能的侵害是致命的,随机读一次磁盘的耗时数量级在几个毫秒,而minflt只有在大量的时候才会对性能产生影响。 二、总结通过对Linux内存治理的介绍,咱们能够看到内存治理须要解决的问题: 调用零碎提供的无限接口操作虚存读写衡量单次调配较大内存和屡次调配较少内存带来老本:管制缺页中断(尤其是majflt)vs 过程占用过多内存升高内存碎片升高内存治理库本身带来的额定损耗在接下来的几篇文章将就ptmalloc,jemalloc,tcmalloc几个经典内存治理库,与大家进一步探讨C++程序罕用的内存治理库的实现原理。 ---------- END ---------- 相干参考: [1] 《Linux通明大页机制在云上大规模集群实际介绍》:https://mp.weixin.qq.com/s/hGjADS9tdHeqS9XR4pkh\_w [2] Writing a Linux Kernel Module — Part 1: Introduction: http://derekmolloy.ie/writing... ...

September 28, 2022 · 1 min · jiezi

关于c++:AVL树

AVL树性质它的左右子树都是AVL树左右子树高度之差的绝对值不超过1(右子树高度 - 左子树高度)(也称为均衡因子)每个节点都有一个均衡因子个别AVL树都是三叉链(左右节点指针和父亲节点指针)AVL树高度为 O(logN)AVL树的工夫复杂度为O(logN)。均衡因子的更新准则: 如果新增节点在父节点的右边,则父节点的均衡因子减1;顺次向上更新如果新增节点在父节点的左边,则父节点的均衡因子加1;顺次向上更新直到以后节点的均衡因子为0才不向上持续更新了如果均衡因子为-2或2,则须要旋转。而后在判断是否须要持续更新。AVL树节点的定义形式template<class K,class V>struct AVLTreeNode //建设节点{ AVLTreeNode<K, V>* _left; AVLTreeNode<K, V>* _right; AVLTreeNode<K, V>* _parent; int _bf; //均衡因子 pair<K, V> _kv; //键值对,存储数据 AVLTreeNode(const pair<K, V>& kv) //构造函数 :_left(nullptr) ,_right(nullptr) ,_parent(nullptr) ,_bf(0) ,_kv(kv) {}};AVL树的四种旋转形式为什么要旋转当插入一个节点时,直接插入可能会导致均衡被毁坏(插入节点的所有先人节点的均衡因子可能会扭转)这时就须要将数据进行旋转例如:当插入 30 节点时,这个树就不是AVL树了,所以将其进行旋转,失去左边的AVL树。右单旋 右单旋代码实现 //右单旋 void RotateR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; Node* parent_parent = parent->_parent; parent->_left = subLR; if (subLR) subLR->_parent = parent; subL->_right = parent; parent->_parent = subL; if (parent == _root) { _root = subL; _root->_parent = nullptr; } else { if (parent_parent->_left == parent) parent_parent->_left = subL; else parent_parent->_right = subL; subL->_parent = parent_parent; } subL->_bf = 0; parent->_bf = 0; }左单旋 ...

September 27, 2022 · 2 min · jiezi

关于c++:本周三全球C大会8大主题近40场专题演讲盛大开启龙蜥2位技术专家参加

零碎级软件是数字世界的基础设施,C++ 自 1985 年由 Bjarne Stroustrup 博士在贝尔实验室创造以来,始终被誉为零碎级编程“皇冠上的明珠”。2022 年 9 月 28-29 日,由高端 IT 征询与教育平台 Boolan 主办的「2022 寰球 C++ 及系统软件技术大会」将于上海隆重召开。本次大会特邀 C++ 之父、美国工程院、ACM、IEEE 院士 Bjarne Stroustrup 以及来自国内外 C++ 与系统软件畛域的巨匠、专家、学者齐聚一堂。 系统软件畛域规模最大、阵容最强、干货最多的大会将围绕 C++ 20 新规范、工程与工具链、架构与设计演变、品质与效力、高性能与低时延、零碎级软件等 8 大主题、40+ 技术大咖及上千位业界同仁,深度探讨 C++ 与零碎级软件技术畛域的最佳工程实际和前沿办法。 龙蜥社区两位资深技术专家也将参加此次大会演讲,将与各领域专家、学者探讨交换,分享内容包含 eBPF 工具的开发和资源优化在多内核版本的实际、现代化工具链在大规模 C++ 我的项目中的实际。 参会嘉宾和议题如下: eBPF 工具的开发和资源优化在多内核版本的实际工夫:分会场A 9 月 28 日下午 16:50-17:40 嘉宾:毛文安,龙蜥社区零碎运维 SIG 负责人 Linux 内核版本经验了 3.x 向 4.x 到 5.x 演进,eBPF 技术的反对也是从 4.x 开始欠缺起来,目前高版本内核曾经反对纯 CORE 形式,而云上服务器有大量的 3.10 内核版本是不反对 eBPF 的,为了让咱们现有的 eBPF 工具在这些存量机器得以反对,享受到 eBPF 带来的红利,咱们移植了eBPF技术到低版本内核,保障一个工具可运行于低、中、高的内核版本。 ...

September 27, 2022 · 1 min · jiezi

关于c++:视频结构化-AI-推理流程

「视频结构化」是一种 AI 落地的工程化实现,目标是把 AI 模型推理流程可能一般化。它输出视频,输入结构化数据,将后果给到业务零碎去造成某些行业的解决方案。 换个角度,如果你想用摄像头来实现某些智能化监控、预警等,那么「视频结构化」可能就是你要用到的技术计划。 不过,也不肯定须要本人去实现,因为各个芯片厂商可能都提供了相似的流程框架: 寒武纪 CNStreamNVIDIA DeepStream以上集体没用过,简略看了下,都受限于只能用厂商自家的芯片。集体教训来说,个别硬件还是须要多家可选的,本人实现一套「视频结构化」还是有必要的。 本文将介绍「视频结构化」的实现思路、技术架构,以及衍生的一些工作。 实现思路有一个 AI 模型与一段视频,如何进行推理呢? 视频流:OpenCV 关上视频流,获取图像帧前解决:图像 Resize 成模型输出的 Shape模型推理:AI 框架进行模型推理,失去输入后处理:将输入解决成冀望的信息 例如,指标检测:解析框的地位和类别,再 NMS 筛选以上是最根底的推理流程,实现得不错 简略工作,这样满足要求就行。但理论工作,可能: 输出 工作接管视频流 相机选型视频起源: 录制视频、RTSP 实时流帧率控制: 个别 5 fps,缩小计算多路并发: 多路视频,并行剖析硬件解码推理 前解决 输出调整: 缩放、转置Batch 合并硬件加速模型推理 硬件选型: Nvidia、华为昇腾、或其余模型解决: 裁剪、转换、量化模型编排: 多任务多模型,有先后关系后处理 输入解析: 推理后果,变为结构化数据硬件加速输入 后果推送其余 视频存储,License链路追踪,耗时剖析以上流程个别称为「视频结构化」:输出多路视频,进行实时剖析,最初输入结构化数据,给到业务零碎。 该流程,这里把它分为了输出、推理、输入,都是一个个工作节点,整体采纳 Pipeline 形式来编排 AI 推理工作。输入输出时,个别会用 RPC 或音讯队列来与业务零碎通信。 整体架构「视频结构化」整体架构,如下: 管道节点管道 Pipeline 这块是次要局部,其实现都是一个个节点: IN 工作接管;视频流解码;帧率控制推理 推理引擎做模型推理,后果进结构化数据;依编排往后持续追踪 追踪依赖推理出的特色;业务不须要,就不编排OUT 后果推送;要预览播放的话,进行视频流编码节点就是个生产消费者,用个阻塞队列很快就能实现。节点间组成一个树,也就是工作编排的后果。节点会有输入输出差别,要约定分明或分几个类型。 节点流程:音讯队列有工作,取出执行,后果进结构化数据,最初发给下一节点的音讯队列。 节点的线程数、队列下限,都可做配置。根据耗时剖析,能够优化调整。 GStreamer 的 pipeline + plugin 的技术架构值得学习。集体没深刻理解,所以不好具体评估,倒见过在输出做插件化解码。NVIDIA DeepStream 间接就基于 GStreamer 开发的。构造数据结构化数据,在整个 Pipeline 里是一直追加欠缺的过程,最初输入时个别 JSON 化推送。 ...

September 23, 2022 · 1 min · jiezi

关于c++:2022升级百度大牛带你结合实践重学C完结无密

download:2022降级百度大牛带你联合实际重学C++完结无密哈希表查找哈希算法的定义与实现1哈希表查找定义哈希技术是在记录的存储地位和它的关键字之间建设一个确定的对应关系,使每个关键字对应一个存储地位。 存储地位=f(关键字) 对应关系称为哈希函数,也称为哈希函数。 哈希技术用于将记录存储在一个间断的存储空间中,称为哈希表或哈希表。哈希技术不仅是一种存储办法,也是一种搜寻办法。 Hash函数可能将两个或多个不同的关键字映射到同一个地址,称这些状况为抵触,而这些抵触的不同关键字称为同义词。 2哈希函数的构造方法3.1间接寻址办法对于关键字age,能够间接用age的数量作为地址,其中f(key)=key。 如果要统计1980年当前出世年份的人口,如下图所示,能够用年份减去1980作为出世年份关键字的地址。此时f(key)=key-1980。 间接关键字去除的线性函数值是哈希地址,哈希函数是: 间接寻址法的哈希函数简略、对立且不会引起抵触,但须要当时晓得关键字的散布,所以实用于小而间断的查找表。 3.2除法和余数法除余数法是结构哈希函数最罕用的办法。假如哈希表长度为M,取一个不大于M但最靠近或等于M的素数P,哈希函数为: 假如咱们有12个记录的关键字来结构哈希表,例如,咱们应用新办法,所以它存储在下标5处。 依据教训,如果哈希表长度为M,通常P是小于等于表长度的最小素数(最好靠近M)或者是不蕴含少于20个素数因子的合数。 解决哈希抵触的3种办法3.1凋谢地址办法3.1.1线性检测办法开放式寻址办法是一旦有抵触就寻找下一个空的散列地址。只有哈希表足够大,总是能够找到空的哈希地址,并且记录将被存储。 在一个简略的例子中,咱们的关键字集是,表长度是12。咱们应用散列函数。 计算前五个数时,都是哈希地址,没有抵触,间接存储。 计算key=37时,发现与25的地位抵触,于是从新计算,37存储在下标2的地位,如图。 当key=48时,咱们计算出和12所在的地位0抵触。持续算,和25的地位抵触,所以始终到都没有空缺,如图。 这种解决抵触的开放式寻址办法称为线性检测办法。 二次检测那时候叫二次检测法。减少正方形操作的目标是为了避免所有关键词都汇集在某个区域。 伪随机检测在有抵触的状况下,用随机函数计算位移,称为随机检测法。 3.2链接地址办法为了防止非同义词的抵触,所有的同义词都存储在一个线性链表中。 对于可能导致许多抵触的散列函数,链办法提供了不会找到地址的保障。 4哈希表的搜寻哈希查找依赖于三个因素:哈希函数、解决抵触的办法和填充因子。 填充因子表中记录的哈希表长度。 哈希表的均匀搜寻长度取决于哈希表的填充因子,而不是间接取决于或。 越大越满,抵触的可能性越大。 4.1哈希表搜索算法的实现哈希表的构造定义如下: 定义胜利1定义不胜利0define HASHSIZE 12 /将哈希表长度定义为数组的长度/定义NULLKEY -32768typedef int状态;/ Status是函数的类型,其值是函数后果状态码,如OK等。/ typedef构造{int elem/数据元素存储基址,动态分配数组*/int计数;/以后数据元素的数量/}哈希表; int m = 0;/哈希表长度,全局变量/哈希表初始化: /初始化哈希表/状态InitHashTable(HashTable *H){int I;m = HASHSIZEh-> count = m;h-> elem =(int )malloc(m sizeof(int));for(I = 0;我h-> elem[I]= null key;退货OK;}作为哈希函数的余数办法: /哈希函数/int Hash(int key){返回键% m;/除法和余数法/}哈希表插入算法: /将关键字插入哈希表/void InsertHash(HashTable *H,int key){int addr = Hash(key);/查找哈希地址/while (H->elem[addr]!= NULLKEY) /如果不为空,则抵触/{addr =(addr+1)% m;/凋谢寻址办法的线性检测/}h-> elem[addr]= key;/插入关键字,直到有空格为止/}在代码中插入关键字时,首先计算哈希地址。如果以后地址不是空关键字,则示意存在抵触。此时咱们应用线性检测的凋谢寻址办法进行重寻址,这里也能够改为链地址法等其余抵触解决办法。 ...

September 23, 2022 · 1 min · jiezi

关于c++:通用ORM的设计与实现

介绍咱们通用的ORM,基本模式都是想要脱离数据库的,简直都在编程语言层面建设模型,由程序去与数据库打交道。尽管脱离了数据库的具体操作,但咱们要建设各种模型文档,用代码去写表之间的关系等等操作,让初学者一时如坠云雾。我的想法是,将关系数据库领有的欠缺设计工具之劣势,来实现数据设计以提供构造信息,让json对象主动映射成为规范的SQL查问语句。只有咱们了解了规范的SQL语言,咱们就可能实现数据库查问操作。 依赖关系本我的项目依赖 自己的 另一个我的项目 Zjson,此我的项目提供简洁、不便、高效的Json库。该库使用方便,是一个单文件库,只须要下载并引入我的项目即可。具体信息请移步 gitee-Zjson 或 github-Zjson 。 设计思路ZORM 数据传递采纳json来实现,使数据规范能从最前端到最初端达到谐和对立。此我的项目指标,岂但在要C++中应用,还要作为动态链接库与node.js联合用应用,因而心愿能像javascript一样,简洁不便的操作json。所以后行建设了zjson库,作为此我的项目的后行我的项目。设计了数据库通用操作接口,实现与底层实现数据库的拆散。该接口提供了CURD规范拜访,以及批量插入和事务操作,根本能满足平时百分之九十以上的数据库操作。我的项目根本指标,反对Sqlite3,Mysql,Postges三种关系数据库,同时反对windows、linux和macOS。 我的项目进度当初曾经实现了sqlit3与mysql的所有性能,postgres也做了技术筹备。 我抉择的技术实现形式,基本上是最底层高效的形式。sqlit3 - sqllit3.h(官网的规范c接口);mysql - c api (MySQL Connector C 6.1);postgres - pqxx 。 工作列表: [x] Sqlite3 实现 [x] linux[x] windows[x] macos[x] Mysql 实现 [x] linux[x] windows[x] macos[ ] Pstgre 实现 [ ] linux[ ] windows[ ] macos数据库通用接口利用类间接操作这个通用接口,实现与底层实现数据库的拆散。该接口提供了CURD规范拜访,以及批量插入和事务操作,根本能满足平时百分之九十以上的数据库操作。 class ZORM_API Idb { public: virtual Json select(string tablename, Json& params, vector<string> fields = vector<string>(), Json values = Json(JsonType::Array)) = 0; virtual Json create(string tablename, Json& params) = 0; virtual Json update(string tablename, Json& params) = 0; virtual Json remove(string tablename, Json& params) = 0; virtual Json querySql(string sql, Json params = Json(), Json values = Json(JsonType::Array), vector<string> fields = vector<string>()) = 0; virtual Json execSql(string sql, Json params = Json(), Json values = Json(JsonType::Array)) = 0; virtual Json insertBatch(string tablename, Json& elements, string constraint = "id") = 0; virtual Json transGo(Json& sqls, bool isAsync = false) = 0; };实例结构全局查问开关变量:DbLogClose : sql 查问语句显示开关parameterized : 是否应用参数化查问Sqlite3: Json options; options.addSubitem("connString", "./db.db"); //数据库地位 options.addSubitem("DbLogClose", false); //显示查问语句 options.addSubitem("parameterized", false); //不应用参数化查问 DbBase* db = new DbBase("sqlite3", options);Mysql: Json options; options.addSubitem("db_host", "192.168.6.6"); //mysql服务IP options.addSubitem("db_port", 3306); //端口 options.addSubitem("db_name", "dbtest"); //数据库名称 options.addSubitem("db_user", "root"); //注销用户名 options.addSubitem("db_pass", "123456"); //明码 options.addSubitem("db_char", "utf8mb4"); //连贯字符设定[可选] options.addSubitem("db_conn", 5); //连接池配置[可选],默认为2 options.addSubitem("DbLogClose", true); //不显示查问语句 options.addSubitem("parameterized", true); //应用参数化查问 DbBase* db = new DbBase("mysql", options);智能查问形式设计查问保留字:page, size, sort, fuzzy, lks, ins, ors, count, sum, grouppage, size, sort, 分页排序 在sqlit3与mysql中这比拟好实现,limit来分页是很不便的,排序只需将参数间接拼接到order by后就好了。 查问示例: ...

September 20, 2022 · 3 min · jiezi

关于c++:2022升级百度大牛带你结合实践重学C完结无密含资料

download:2022降级百度大牛带你联合实际重学C++完结无密含材料一条SQL语句从头到尾1.一段SQL是怎么诞生的?SQL语句都诞生在客户端。生成一条SQL次要有两种形式,一种是开发人员自己手工编写,另一种是相干的ORM框架主动生成。一般MySQL运行过程中收到的SQL大多是ORM框架生成的,比如Java中的MyBatis和Hibernate框架。同时,SQL生成的时机一般与用户的请求无关。当用户在零碎中执行操作时,通常会生成一条SQL。例如,咱们在阅读器上输出以下URL: 此时会先请求掘金的服务器,而后掘金外部实现中的ORM框架会根据请求的参数生成一条SQL,类似于上面的伪SQL: select * from金爵_article其中userid = 862486453028888 这个SQL大抵意义是:根据用户请求的“作者ID”,查问掘金数据库文章表中该作者的所有文章信息。从下面的案例可能显著感觉到,在用户阅读器上看到的数据一般来自于数据库,而数据库执行的SQL来自于用户的操作。这两者是互补的,包含任何写操作(增加、删除、更改),本质上也会转换成SQL的片段。让我举一个简略的例子: 请求URL(请求URL)https://www.xxx.com/user/regi... 请求参数(请求参数){User_name:“竹子爱熊猫”,user _ pwd:“123456”,用户_性别:“男”,用户_电话:“18888888888”,......} 这里对用户明码的处理不够谨严,不做加密也不必在意~复制代码例如,在上述用户注册的情况下,当用户点击网页上的“注册”按钮时,将向目标网站的服务器发送post请求,而后将根据请求参数生成一条SQL,如下所示:insert into table_user(用户名,用户明码,用户性别,用户电话,....)价值观(“竹子爱熊猫”、“123456”、“男”、“188888888”,...);复制代码也就是说,一条SQL的诞生源于一个用户的请求。在开发程序时,SQL的一般逻辑会由业务层的代码决定,而具体的SQL语句会根据用户的请求参数和事先定制的“SQL骨架”做出。当然,在Java程序或者其余语言编写的程序中,只能生成SQL,SQL的真正执行需要数据库来实现。第二,SQL在执行之前将经历的一个过程通过上一步,一个完整的SQL就诞生了。为了让SQL失常执行,咱们将首先获得一个数据库连接对象。上一篇对于MySQL架构的文章,已经讲过MySQL的连接层有一个叫“连接池”的小工具的保护,不过相信大家都接触过这个货色,比如C3P0,德鲁伊,DBCP等等在Java里。 至此,咱们可能在这里思考一个问题。数据库保护自己的连接池,为什么咱们还需要在MySQL客户端保护一个数据库连接池?接下来咱们聊聊。 2.1、数据库连接池的必要性家喻户晓,当你要用Java创建数据库连接时,首先会读取配置文件中的连接地址、账号密码等信息,而后发动网络请求,根据配置的地址信息获取数据库连接对象。在这个过程中,因为涉及到网络请求,此时必然会经历TCP三次握手的过程。同时,在获得连接对象并实现SQL操作后,将开释数据库连接。这时分就需要经历TCP挥动四次的过程。 从下面的描述中可能清晰地感知到,Java中创建和敞开数据库连接的过程实际上耗费了大量的成本,而且程序上线后,还需要频繁的数据库操作。所以,如果每次操作数据库都获得一个新的连接对象,那么整个Java程序至多有四分之一的工夫要做TCP三次握手/四次wave的工作,对整个零碎的后果不堪设想。.... 正是因为以上原因,才出现了家喻户晓的“数据库连接池”。“数据库连接池”的思维和“线程池”是一样的,会把数据库连接到这个宝贵的资源上,用池技术来保护这个资源。也意味着当前需要进行数据库操作时,不需要自己建立连接,而是可能间接从“数据库连接池”中获取,用完之后放回连接池,达到重用的成果。 当然,连接池中保护的连接对象不会一直存在。当长时间不执行SQL操作时,连接池也会销毁这些连接对象,必要时再从新创建。然而什么时候创建,什么时候销毁,限度连接数等等,都是交给连接池来实现,不需要开发者自己关注。 好了~,回到后面抛出的问题,为什么需要用MySQL连接池在客户端保护一个连接池? 这个问题相信每个人心里都有一些答案。原因很简略。两者都使用池化技术来重用资源,俭约开销,提高性能,但针对的方向不同。 MySQL的连接池次要是为了重用线程,因为每一个数据库连接都会被MySQL中的一个线程保护,而每一次连接对象调配给一个客户端,都需要经历创建线程、调配堆栈空间这样沉重的工作...这个过程需要工夫,资源开销也不小,所以MySQL通过使用池化技术来解决这些问题。客户端的连接池次要是为了重用数据库连接,因为每一个SQL操作都需要经历TCP三次握手/四波的过程,同样耗时耗力,占用资源。所以也采纳了池化技术来解决这个问题。 其实也可能这样理解,MySQL连接池保护的是工作线程,而客户端连接池保护的是网络连接。 2.2.在执行SQL之前会发生什么回到本文的主题,当生成完整的SQL时,咱们将首先尝试在连接池中获取一个连接对象。接下来会发生什么? 在尝试从连接池中获取连接时,如果此时连接池中有空闲的连接,可能间接获取重用。但如果不是,你首先要判断以后池中的连接数是否达到了最大数量。如果连接数已满,以后线程需要等待其余线程开释连接对象。如果没有,您可能间接创建一个新的数据库连接来使用。 假设此时连接池中没有空闲的连接,需要再次创建新的连接,那么首先会发动一个网络请求来建立连接。 ①首先,将考据客户端的用户名和明码是否正确: 如果用户名不存在或明码谬误,将抛出错误代码1045和谬误消息。如果用户名和明码通过考据,请转到步骤②。 ②必定MySQL连接池中是否有空闲线程: 存在:间接从连接池中调配一个空闲线程来保护以后客户端的连接。否:创建一个新的工作线程(映射内核线程,调配堆栈空间...). worker线程会先查问MySQL自己的用户权限表,获取以后登录用户的权限信息,并进行授权。 至此,执行SQL前的筹备工作已经实现,执行SQL的通道已经打开。下一步是筹备执行SQL语句,工作线程将等待客户端传送SQL。三。SQL语句是如何在数据库中执行的?通过连接层的一系列工作,客户端会通过连接发送要执行的SQL语句,而后由MySQL服务层进行处理。然而根据用户的操作不同,MySQL执行SQL语句时会有一些区别,SQL语句指的是读操作和写操作。这两条SQL语句的执行过程是不同的。咱们先来看看select语句的执行过程。3.1.一个查问SQL的执行过程在分析查问SQL的执行过程之前,咱们先模拟一个案例进行后续分析: SQL语句Select id from ZZ _ user 其中user sex =男性,user_name =竹四号";-表格数据 +|用户标识|用户名|用户性别|用户电话|+| 1 |竹① |男| 1888888888 || 2 |竹② |男| 1358888888 || 3 |竹③ |男| 1568888888 || 4 |熊猫① |女| 1348888888 || 5 |熊猫② |女| 1858888888 || 6 |竹④ |男| 17777777 || 7 |熊猫③ |女| 166666666 |+

September 19, 2022 · 1 min · jiezi

关于c++:2022升级百度大牛带你结合实践重学C含资料

download:2022降级百度大牛带你联合实际重学C++含材料5 Spring5源代码16-@EnableWebMvc正文原理1.需要和運用一旦我們將九個自定義組件放入容器,DispatcherServlet就會初始化,以查看容器中是否有我們自己的組件,因此我們不需要自己的默許組件。我們的許多默許功能都喪失了。我們的期望: 您自己的組件能夠失效。SpringMVC的默許還是管用的。能夠運用@ enablewemvc+webmvconfiguration。@EnableWebMVC會導入9個組件到容器中,並且都有條目【我們能夠用WebMvcConfigurer自定義】,而不是默許運用配置文件。 2.@EnableWebMvc@保留(RetentionPolicy。運轉時間)@Target(ElementType。類型)@已記载@ Import(delegatingwebmvc configuration . class)public @interface EnableWebMvc {}復製代码 我們發現,實践上是經過@Import正文在容器中注册了一個組件delegatingwebmvconfiguration,所以现在的核心是delegatingwebmvconfiguration類做了什麼? 3.托付web MVC配置 兩個感知接口自動將ApplicationContext對象和ServletContext對象注入該組件。现在我們要帶著兩個問題來看看這類源代码? 爲什麼這個組件能夠讓自定義配置類失效?爲此組件定義了哪些默許配置? 3.1托付webmvconfiguration源代码DelegatingWebMvcConfiguration類非常简單,只有一個字段配置器,它保存所有的配置類對象。另外要注意一個辦法,set configurator(list configurator)辦法,用@Autowired(required = false)正文,會自動執行。@ Configuration(proxybean methods = false)公共類托付WebMvcConfiguration擴展WebMvcConfigurationSupport { //組合模式,組合所有配置類。private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); /***此處增加了正文@Autowired(必填= false)。*然前办法將在屬性填充階段執行,其中辦法參數來自容器。*會自動沈著器中找到匹配類型的bean,然後反映執行辦法。*/@自動連線(必须=假)公共void匯合配置器(列表配置器){如果(!CollectionUtils.isEmpty(配置器)){//將容器中的所有WebMvcConfigurer對象放入WebMvcConfigurerCompositethis . configurers . addwebmvc configurers(配置器);}} /**/ /***以下辦法类似。*向WebMvcConfigurerComposite的每個配置類增加配置的詳細過程參見3.1.1。*/@掩蓋受維護的void配置路径匹配(路径匹配配置器配置器){this . configurers . configurepathmatch(configurer);} ... /**/ //此辦法將獲取配置類定義的獨一考證程序。@掩蓋@Nullable受維護的考證程序getValidator() {返回this . configurers . get validator();} //此辦法將獲取配置類定義的獨一MessageCodesResolver。@掩蓋@Nullable受維護的MessageCodesResolver getMessageCodesResolver(){返回this . configurers . getmessagecodesresolver();}}復製代码能夠看到,在DelegatingWebMvcConfiguration組件的屬性填充階段,會自動找到容器中所有類型爲WebMvcConfigurer的bean對象,然後以它們爲參數調用set configurators(list configurators)辦法,所有配置類對象都會放入WebMvcConfigurerComposite中。此外,它還重寫了父類的一些辦法(模板辦法模式)來向配置類注册配置,並獲取配置類中的一些配置對象,如Validator或MessageCodesResolver。3.2 WebMvcConfigurerComposite上面是這個類的源代码,辦法很简單,次要注意以下四點: 該類保存所有配置類對象。增加配置時,該配置將注册到所有配置類對象。getValidator()辦法只能由一個配置類重寫,並且只允許一個配置類返回一個Validator對象。getMessageCodesResolver()辦法只能由一個配置類重寫,並且只允許一個配置類返回MessageCodesResolver對象。 WebMvcConfigurerComposite類实现WebMvcConfigurer { //持有配置類對象公有最終列表托付= new ArrayList(); ...

September 18, 2022 · 1 min · jiezi

关于c++:CC气象数据中心实战手把手教你做工业级项目源码齐全

download:C/C++气象数据中心实战,手把手教你做工业级我的项目(源码齐全)应用SpringBoot配置文件的具体阐明1.创立一个SpringBoot我的项目二。配置文件的类型从上一节的图中能够看出,src/main/resources目录中的application.properties文件是创立的默认全局配置文件。 这是一种以。属性后缀。 还有一种以结尾的YAML文件类型。yml suffix-application.yml/application.yaml. YAML是一种比属性格局年老得多的配置格局,属性格局在云原生中应用。三。配置文件#的语法格局3.1利用类型.属性#Properties是java中常见的配置文件类型,其语法格局为key=valve。复制 ` key=value '复制代码应用示例:复制 ` server.port = 80server.ip = 127.0.0.1 app.property.key = pronameapp.property.name = tomapp.list = 1,2,3 还有这个语法?增加启动命令:- spring.profiles.active=devspring . profiles . active = $ { spring . profiles . active } #读取启动命令参数 属性占位符:应用${var}语法来援用已定义属性的值。app.desc =您的姓名是${ app . property . name } `复制代码3.2 application.yml类型#将上述属性格局更改为yml格局:复制 `服务器:端口:80ip: 127.0.0.1 应用程序:属性:关键字:proname姓名:汤姆列表:[1,2,3]desc:你的名字是${app.property.name} 春天:个人资料:active:$ { spring . profiles . active } ` 0复制代码例如,对于一个数组,能够这样写:复制 `人:喜好:篮球跑步吗?-浏览复制代码你也能够这样写:复制 `人:喜好:[篮球、跑步、浏览]复制代码 YAML反对以下数据类型: 对象:键值对的汇合,也称为映射)/散列)/字典。数组:按顺序排列的一组值,也叫序列)/列表。标量:繁多的、不可分割的值。 3.3配置随机值SpringBoot外部提供了一个随机的。*属性,专门用于生成随机值。 属性random.int随机生成正负整数random.int(max)随机生成整数random.int(min[0,max]随机生成整数random.long随机生成正负长整数random.long(max)随机生成[0,长整数random区间的long(min,max)随机生成长整数random。[min,max]区间的UUID随机生成一个uuid字符串(包含'-'字符)。' '示意除上述字符之外的其余字符,用于随机生成32位字符串。配置示例:复制 ` int-val=${random.int}int-range-val=${random.int(2)}uuid-val=${random.uuid} `复制代码四。配置文件的加载程序#当SpringBoot启动时,以下地位的application.properties或application.yml将作为默认配置文件加载。 ...

September 17, 2022 · 1 min · jiezi

关于c++:名称空间

随着我的项目增大,不同的厂商的类库的名称可能会呈现抵触,比方,有可能两个类库同时都定义了名称为List、Tree、Node的类,然而定义的形式不兼容,为防止上述问题,C++提供了名称空间工具,来限定不同名称的作用域。 1、传统的C++名称空间 首先须要介绍三个术语:申明区域、潜在作用域,作用域 申明区域:申明区域为在其中进行申明的区域,比方在函数外申明全局变量,对于这种变量,其申明区域为其申明所在的文件。而对于在函数中申明的变量,其申明区域为其申明所在的代码块。 潜在作用域:变量的潜在作用域从申明点开始,到申明区域的结尾,所以潜在作用域比申明区域要小,起因是,变量只有定义了能力应用。 作用域:变量对程序而言可见的范畴被称为作用域。 潜在作用域和作用域的区别:在搞懂区别之前,须要阐明一个点,变量在潜在作用域内并不是始终都可见的,它会被嵌套申明中申明的同名变量暗藏,如果在代码块中申明的一个同名的变量将会暗藏代码块外申明的同名变量,此时在该代码块中,内部申明的变量就不可见了。用简略的话来说,潜在作用域一般来说是间断的一块,然而作用域有可能是断断续续的块连贯在一起的。 int main(){ int goo=0;//第一个goo作用域与潜在作用域同时失效 ...... for(int i=0;i<10;i++) { int temp=0; .... int goo=temp*1;//第二个goo作用域失效,暗藏第一个goo ....//在代码块完结处,第二个goo作用域完结,潜在作用域也完结。 } ......//第一个goo不在被暗藏,因而作用域持续 return 0;}2、新的名称空间个性 定义一种新的申明区域来创立命名的名称空间,提供一个申明名称的区域,以下代码应用新的关键字namespace创立了Jack名称空间。 namespace Jack{ double pail; void fetch(); int pal; struct Well{};} 名称空间既能够是全局的,也能够位于另一个名称空间,除了用户定义的名称空间外,还存在全局名称空间,全局变量即位于该全局名称空间,其对应于文件级申明区域。 名称空间是凋谢的,其既能够把名称退出到已有的名称空间中 namespace Jack{ char* goose(const char*);} 也能够在该文件前面再次应用Jack名称空间来提供该函数的代码 namespace Jack{ void fetch() { }} 拜访给定名称空间中的名称的办法为应用作用域解析运算符::。 1、using申明和using编译指令using申明:将特定的名称增加到它所属的申明区域中,下述代码中,在main函数中应用using申明Jill名称空间中的fetch变量,它防止了将另一个局部变量也命名为fetch,同时fetch将笼罩同名的全局变量。 namespace Jill{ double bucket(double n){} double fetch; struct Hill{}}char fetchint main(){ using Jill::fetch; double fetch; cin>>fetch;}using编译指令:其指令格局次要由using+namespace+名称空间名,它使得名称空间中的所有名称都能够应用,而不须要应用作用域解析运算符。 ...

September 16, 2022 · 1 min · jiezi

关于c++:C函数模板的具体化

在代码中申明函数模板的时候,是不会生成函数定义的,当编译器应用模板为特定类型生成函数定义时,失去的是模板实例。例如如下代码,这样的模板并非函数定义。 template<class T>void Swap(T &a, T &b){ T temp; temp = a; a = b; b = temp;}函数模板的具体化又分为隐式实例化、显示实例化、显示具体化。1、隐式实例化 int main(){ int a = 10, b = 20; Swap(a, b);}在上述代码中,函数调用Swap(i,j)导致编译器生成Swap实例,这种实例化称为隐式实例化,因为编译器之所以晓得须要进行定义,是因为程序调用了Swap函数时提供了int参数,这种实例化的形式存在效率低下的毛病,因为其无奈在程序编译时就生成函数定义。2、显示实例化显示实例化能够解决隐式实例化的毛病,其能够间接命令编译器创立特定的实例,其语法为如下template void Swap<int>(int, int);3、显示具体化显示具体化次要针对非凡的数据类型,如构造体,其能够对底层的模板进行改变,从而使其针对这种非凡的数据类型执行特定的操作。例如以下代码,我申明了一个构造体,想要只替换构造体中的salary和floor,不替换name,就要应用显示具体化。 struct job{ char name[40]; double salary; int floor;};template<> void Swap<job>(job&a, job&b){ double t1; int t2; t1 = a.salary; a.salary = b.salary; b.salary = t1; t2 = a.floor; a.floor = b.floor; b.floor = t2;}因而调用时,显示具体化将会优先于惯例模板。

September 10, 2022 · 1 min · jiezi

关于c++:c-value-category

微软官网解释 示例 glvalueg是generalize的意思,glvalue是个形象的概念,是lvalue和xvalue的并集 lvalue左值字面意思是能够放在右边的值,包含成员变量和能返回一个左值的函数 int main(){ int i, j, *p; // Correct usage: the variable i is an lvalue and the literal 7 is a prvalue. i = 7; // Incorrect usage: The left operand must be an lvalue (C2106).`j * 4` is a prvalue. 7 = i; // C2106 j * 4 = 7; // C2106 // Correct usage: the dereferenced pointer is an lvalue. *p = i; // Correct usage: the conditional operator returns an lvalue. ((i < 3) ? i : j) = 7; // Incorrect usage: the constant ci is a non-modifiable lvalue (C3892). const int ci = 7; ci = 9; // C3892}xvaluex是expiring,xvalue意思是行将走完生命周期的值,xvalue有地址但程序无奈进入,例如函数返回右值援用的表达式,或者应用move语句这类传入的参数,这种参数快死掉了,就叫做xvalue,例如1 + 1, move(a), static_cast<>({xvalue}) ...

September 4, 2022 · 1 min · jiezi

关于c++:OneFlow源码阅读7静态图与运行时

oneflow动态图的训练效率远高于动态图(eager模式)。本文试图通过一个简略例子,联合0.8.0的代码,看一下动态图和运行时的实现机制。在开始之前,倡议先读一下参考资料中《OneFlow框架的零碎设计》等系列文章。对动态图、运行时的基本概念和设计理念有根本的理解,会更容易了解代码。 1 代码示例上面的示例代码来自官网文档,是一个线性模型的前向计算。后续次要基于这段代码进行剖析。 import oneflow as flowimport oneflow.nn as nnclass ModuleMyLinear(nn.Module): def __init__(self, in_features, out_features): super().__init__() self.weight = nn.Parameter(flow.randn(in_features, out_features)) self.bias = nn.Parameter(flow.randn(out_features)) def forward(self, input): return flow.matmul(input, self.weight) + self.biaslinear_model = ModuleMyLinear(4, 3)class GraphMyLinear(nn.Graph): def __init__(self): super().__init__() # ModuleBlock self.model = linear_model def build(self, input): # ModuleBlock.__call__ return self.model(input)graph_mylinear = GraphMyLinear()input = flow.randn(1, 4)out = graph_mylinear(input)print(out)2 oneflow包的初始化import oneflow在初始化包时,与动态图相干的次要操作如下: GetEnv EnvGlobalObjectsScope::Init 启动各个节点的管制面网络连接初始化VM启动各个节点的数据面网络连接初始化KernelObserverNewDefaultSession RegsiterSession 创立 Session,并注册为 default session创立 Python MultiClientSession 并保留到dict,但并不 TryInit ...

September 2, 2022 · 3 min · jiezi

关于c++:Brpc-服务端收包源码分析一

大家好,我是dandyhuang,brpc在c艹届还是比拟牛逼的rpc框架,本次带来brpc的server端的源码剖析。剖析源码前,大家先搭建好环境,有利于代码调试和了解。依照brpc框架中example的echo_c++为例子,并且将protobuf中,编译出的两头文件echo.pb.cc和.h保留,有利于咱们更好的代码了解。 server端应用namespace example {class EchoServiceImpl : public EchoService {public: EchoServiceImpl() {}; virtual ~EchoServiceImpl() {}; virtual void Echo(google::protobuf::RpcController* cntl_base, const EchoRequest* request, EchoResponse* response, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = static_cast<brpc::Controller*>(cntl_base); response->set_message(request->message()); if (FLAGS_echo_attachment) { cntl->response_attachment().append(cntl->request_attachment()); } }};int main(int argc, char* argv[]) { // Parse gflags. We recommend you to use gflags as well. GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true); brpc::Server server; // 继承proto文件 example::EchoServiceImpl echo_service_impl; if (server.AddService(&echo_service_impl, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) { LOG(ERROR) << "Fail to add service"; return -1; } butil::EndPoint point; point = butil::EndPoint(butil::IP_ANY, FLAGS_port); // Start the server. brpc::ServerOptions options; options.idle_timeout_sec = FLAGS_idle_timeout_s; if (server.Start(point, &options) != 0) { LOG(ERROR) << "Fail to start EchoServer"; return -1; } // Wait until Ctrl-C is pressed, then Stop() and Join() the server. server.RunUntilAskedToQuit(); return 0;}总体代码还是比拟简洁,如果可能依据IDL主动代码生成那样就更完满了。话不多说,间接开撸源码 ...

August 31, 2022 · 17 min · jiezi

关于c++:类应用队列模拟

背景:Heather银行打算在Food Heap超市开设一个ATM。Food Heap超市的管理者放心排队期待应用ATM的人流会烦扰超市的交通,心愿限度排队期待的人数。Heather银行心愿对顾客排队等待时间进行估测。 工作:自行设计一个队列的类和顾客的类,顾客达到的工夫随机,并且编写一个程序来模仿顾客和队列的交互。 思路:首先设计队列类,队列是一个尾进头出的构造,若采纳数组来示意队列,删除队列头部元素,须要将整体的元素往前挪动一格,操作较为繁琐,应用链表的数据结构来示意队列,删除队列首元素时,只需针对单个元素,减少队列元素时,只须要扭转地址。链表与数组相比,链表查找元素较为麻烦,增减元素较为不便。 队列类的设计1、首先设计类的私有接口 队列所能包容的项目数应该要有限度,因而应该在类中设计一个const属性来存储队列所能存储的最大数目。队列可能创立空队列,所以在队列类的构造函数中该当设置初始化属性的参数可能查看队列是否为满,所以应该设置一个bool函数,还想到要有一个类中现有的items的属性,通过这个items的大小与最大数目来进行比拟从而判断队列是否为满查看队列是否为空,与队列是否为满相相似。须要一个函数成员可能返回以后队列中的数目(重点)须要一个插入队列的成员函数和删除队列成员的成员函数,波及到链表的删除和增加,因而在类中应该各设置一个指向头部和指向尾部的指针。class Quene{public: Quene(int qs); ~Quene(); bool isempty() const; bool isfull() const; int countQuene() const; bool enquene(const Item& item); bool dequene(Item item);2、类的公有局部申明除上述提到的公有局部以外,针对链表数据结构,应该设计一个结点构造,结点构造蕴含数值和指向下一个结点的地址。 struct Node{ Item item; Node* next;}class Quene{public: Node* first; Node* rear; int items; const int Maxitems;上述代码引出一个问题:是应该在类中申明构造体,还是在全局中进行申明。全局中进行申明的话,作用域为整个文件,若其余头文件也申明了这个结点定义,当一起蕴含时,容易呈现抵触。若在类中申明构造,则其作用域为类,则不必放心抵触问题。若申明在公有局部,则只能类内进行应用,若在私有局部申明,要在类外应用,只需Quene::Node。 最初队列的类私有成员和公有成员申明: class Quene{private: struct Node { Item item; Node* next; } Node* first; Node* rear; int items; const int Maxitems;public: Quene(int qs); ~Quene(); bool isempty() const; bool isfull() const; int countQuene() const; bool enquene(const Item& item); bool dequene(Item item);3、类的实现 ...

August 30, 2022 · 3 min · jiezi

关于c++:c-单例模式

// 探索单例模式以及单例模式的线程平安问题// meyer's singleton// 懒汉模式的最优雅版本class singleton{private: singleton(/* args */); ~singleton(); singleton(const singleton &); singleton operator=(const singleton &);public: static singleton &getInstance() { static singleton instance; return instance; }};

August 27, 2022 · 1 min · jiezi

关于c++:ABAQUS-稳态动力学求解纯理论公式

本文用于阐明:abaqus谐响应分析的模态叠加原理,大部分来自abaqus Document的theory 局部。具体公式推导的过程要查《构造动力学》0. 总括基于模态的谐响应分析,能够通过扫频的形式求解频率范畴内构造的线性稳态响应状况。阻尼是和频率相干的,但模态叠加法只须要晓得n个模态阻尼即可推广到其余频率范畴(起因详见文内公式)。 1. 谐响应分析的目标用来求解构造在间断谐波激励下的线性响应.求解稳态动力学响应有三种办法:subspace,direct,modal。base modal的办法是利用前一个剖析步提取进去的一系列模态特色计算稳态解。 2. ABAQUS的求解原理2.1 特征值提取对于一个具备N个自由度的多自由度零碎,可用N个独立的广义坐标形容零碎的静止状态: $$a^{N\times1}=\{a_1,a_2,a_3,...,a_N\}^{T}$$ 对于N自由度的零碎,肯定能够找到N个固有频率\( w_{\alpha} \)以及绝对应的振型\( \phi_{\alpha}^{N\times1} \)【\( \alpha=1...n,n是提取的模态的数目 \)】 。\( \phi^{N} \)右边的矩阵是\( M\times N \)的,等号左边是0,所以\( \phi^{N} \)是\( N\times 1 \)的。 所谓振型按我的了解就是共振时,构造的一个形态。用数学形式示意就是一个特定的解向量\( \phi_{\alpha}^{N} \)将\( \phi_{\alpha}^{N\times 1} \)组装成 \( Nxn \)矩阵\( \Phi \),其中每一列都蕴含一个特色模态。 2.2 模态叠加有阻尼的构造动力学方程: 模态叠加用矩阵模式写为 $$u^{N\times1}=\Phi^{N\times n} q^{n\times 1}$$ 列矢量\( q \)——模态自由度(待求)在静止方程中插入模态叠加表达式,代入动力学方程: $$M\Phi \ddot{q}+C\Phi \dot{q}+K\Phi q=f(t)^{N \times1}$$ 左乘\( \Phi^{T} \)后失去: $$\Phi^{T}M\Phi \ddot{q}+\Phi^{T}C\Phi \dot{q}+\Phi^{T}K\Phi q=\Phi^{T}f(t)^{N\times 1}$$ 此时,原方程组现已从求解 N 个变量简化为 n 个变量,右侧\( \Phi^{T}f(t)^{N\times 1} \) 为模态载荷,是外载荷在每个特色模态上的投影。 ...

August 18, 2022 · 2 min · jiezi

关于c++:数据缓冲区

\r 和 \n 的区别\r 示意回车 (回车示意换到以后行的最开始)\n 示意换行(换行只是换到下一行)留神:然而在理论应用时,\n 就间接示意了 \r\n 回车换行。缓冲区的概念行缓冲:常见的是对显示器进行刷新数据时 即必须缓冲区中一行填满了或者遇到 \n 才会输入到显示器全缓冲:对文件进行写入时采纳全缓冲 行将整个缓冲区填满才会刷新到磁盘中。无缓冲:即刷新数据时没有缓冲区。行缓冲示例一:下列代码执行后的后果是:进行5秒后才显示 hello world printf 这行代码是先执行的然而 printf 中没有 \n ,并且缓冲区中的一行并没有填满,所以没有输入到显示器所以继续执行上面的 sleep 代码在程序完结后会刷新缓冲区,将缓冲区的内容输入到显示器,所以最初依然会显示。void test(){ printf("hello world"); //退出 \n 后就会立刻输入到显示器了。 sleep(5); }行缓冲示例二下列代码显示后果为:倒计时,并且下一次的数字会笼罩上一次的数字。因为 \r 只是回车,并未换行,所以仍然会在之前那一行持续输入并且回车后,会回到这一行的起始地位,所以笼罩了上一次的值。#include <unistd.h>void test(){ int i = 10; while(i) { printf("%2d\r",i); //%2d 示意显示两个字符 fflush(stdout); //fflush是一个库函数,用来立刻刷新缓冲区输入到显示器中 sleep(1); i--; } }全缓冲与无缓冲示例一#include <stdio.h>#include <unistd.h>#include <string.h>int main(){ //C语言函数 printf("hello printf\n"); fprintf(stdout,"hello fprintf\n"); //零碎函数 const char * msg = "hello write\n"; write(1,msg,strlen(msg)); fork(); return 0;} ...

August 18, 2022 · 1 min · jiezi

关于c++:ROS教程Xavier

原文链接 1.设置当前工作空间source devel/setup.bash2.catkin_make程序修改,须要首先运行: catkin_make而后运行roslaunch: roslaunch stixel_ros_cc stixeltest.launch3.rviz的应用新开一个终端运行: rviz   学习更多编程常识,请关注我的公众号: 代码的路

August 18, 2022 · 1 min · jiezi

关于c++:理解qt的qList以及函数传参

数组四种类型栈,堆 qDebug() << "test_stack_heap start"; Entity *entity1 = nullptr; Entity *const *p = nullptr; { MyList<Entity *> myList; entity1 = new Entity(1, "entity1"); myList.push_back(entity1); qDebug() << "myList 地址:" << &myList << ",数组指针变量地址:" << &myList.at(0) << ",数组指针变量指向的内存地址:" << myList.at(0); // 1.传值 qDebug() << "funcParam"; funcParam(myList); // 2.传指针 qDebug() << "funcParamPointer"; funcParamPointer(&myList); // 3.传援用 qDebug() << "funcParamRef"; funcParamRef(myList); p = &(myList.at(0)); qDebug()<< (**p).id(); // myList被删除前(函数体完结主动删除),能够拜访到数组内元素地址,进而取得堆内存里的entity内容运行后果: mylist变量存于栈内存,Entity指针变量存于栈内存(数据量大的时候QList会存数据到堆内存),Entity指针指向的Entity内容存于堆内存生命周期完结后mylist开释,Entity指针变量开释,Entity指针指向的Entity内容不开释(需手动delete) 传参: 传值将mylist的Entity指针变量拷贝复制到list里,此时,list与mylist地址不一样,list的指针变量地址与mylist的指针变量地址不一样,list的指针变量指向的内容与mylist的指针变量指向的内容一样传指针将mylist的地址作为参数传递,此时只会有地址的拷贝,list的地址与mylist的地址将会一样,指针变量的地址也一样,指针变量指向的内容地址也一样传援用传援用与传指针一样栈,栈 qDebug() << "test_stack_stack start"; Entity const *p = nullptr; { MyList<Entity> myList; Entity entity1(1, "entity1"); myList.push_back(entity1); qDebug() << "myList 地址:" << &myList << ",数组内容地址:" << &myList.at(0); // 1.传值 qDebug() << "funcParam"; funcParam(myList); // 2.传指针 qDebug() << "funcParamPointer"; funcParamPointer(&myList); // 3.传援用 qDebug() << "funcParamRef"; funcParamRef(myList); p = &(myList.at(0)); qDebug()<< (*p).id(); // myList被删除前(函数体完结主动删除),能够拜访到数组内元素,取得数组存储的entity内容 } qDebug() << (*p).id(); //此时数组被开释,类指针被开释,无奈再通过其拜访 qDebug() << "test_stack_stack end";运行后果: ...

August 16, 2022 · 5 min · jiezi

关于c++:CC气象数据中心实战手把手教你做工业级项目无密分享

C/C++气象数据中心实战,手把手教你做工业级我的项目|无密分享下载地址:百度网盘Java中如何斯文的处理异样对于后端程序员来说,写Java程序的时候,处理异样是必须要做的事。谬误处理诚然重要,然而若是被谬误处理霸占了大部分逻辑,那么就大错特错了。最近对这一点略有研究,稍微提一些斯文的处理异样的技巧和思路。1 使用异样而不是返回码咱们先看如下代码例子public void demo01(Long userId){ String userName = getUserName(userId);if (StringUtils.isNotEmpty(userName)) { //持续之后的逻辑} else { log.info("没有获取到用户名称");}}复制代码若是执行这段代码的时候,userName为空,会影响接下来的逻辑。可是若是只是输入一段日志,刚写代码的时候,比较熟悉,查看起来容易,然而工夫久了或者后边的同学接手代码的时候就有点烦脑了。最好是间接抛出异样,既然已经影响到接下来的逻辑了,那就抛出异样,阻断过程。如下所示:public void demo02(Long userId){ String userName = getUserName(userId);if (StringUtils.isNotEmpty(userName)) { //持续之后的逻辑} else { throw new BusinessException("没有获取到用户名称");}}复制代码2 使用不可控异样若是使用可控异样,那么在多层封装的时候,需要在每个catch块中申明这个异样,若是在最底层的方法中新增了一个可管制异样,那么每个调用此方法的函数都要新增一个throw语句。就像如下代码所示,当getManager新增一个可控异样,那么demo03绝对应也要新增一个catch块。调用demo03的方法也要新增。以此类推,那么就是从最底层到最高层的一个修改链。public void demo03(Long userId) throws Exception { try { String userName = getManager(userId); //持续之后的逻辑} catch (BusinessException e) { throw e;} catch (Exception e) { throw new Exception(e);}} private String getManager(Long userId) throws Exception { try { //获取以后用户的manager} catch (BusinessException e) { throw new BusinessException("获取manager失败");} catch (Exception e) { throw new Exception(e);}return "manager";}复制代码3 给异样提供更多的信息当抛出异样的时候,提供更多的信息,有助于找到问题并疾速解决。能从谬误日志中获取到足够多的信息,来准确分析发生谬误的原因,是一件如许美妙的事件。如下例子,通过错误信息可能看到是获取谁的manager失败了,查看数据库和代码逻辑可能疾速定位问题。若是有其余信息,一并传入会有更大的帮助。public void demo04(Long userId) throws Exception { ...

August 14, 2022 · 1 min · jiezi

关于c++:C基础知识

原文链接 1 static关键字加了 static 关键字的全局变量只能在本文件中应用。 static 定义的动态局部变量调配在数据段上,一般的局部变量调配在栈上,会因为函数栈帧的开释而被开释掉。 1.1 全局动态变量在全局变量前加上关键字 static,全局变量就定义成一个全局动态变量。内存中的地位:动态存储区,在整个程序运行期间始终存在。初始化:未经初始化的全局动态变量会被主动初始化为 0(主动对象的值是任意的,除非他被显式初始化);作用域:全局动态变量在申明仅在本文件可见,他的文件之外是不可见的,精确地说是从定义之处开始,到文件结尾。 1.2 部分动态变量在局部变量之前加上关键字 static,局部变量就成为一个部分动态变量。内存中的地位:动态存储区,在整个程序运行期间始终存在。初始化:未经初始化的全局动态变量会被主动初始化为 0(主动对象的值是任意的,除非他被显式初始化);作用域:作用域仍为部分作用域,当定义它的函数或者语句块完结的时候,作用域完结。然而当部分动态变量来到作用域后,并没有销毁,而是依然驻留在内存当中,只不过咱们不能再对它进行拜访,直到该函数再次被调用,并且值不变; 1.3 动态函数在函数返回类型前加 static,函数就定义为动态函数。函数的定义和申明在默认状况下都是 extern 的,但动态函数仅在本文件可见,不能被其余文件所用。函数的实现应用 static 润饰,那么这个函数只可在本 cpp 内应用,不会同其余 cpp 中的同名函数引起抵触;warning:在头文件中申明非static 的全局函数,在 cpp 内申明static 的全局函数,如果你要在多个 cpp 中复用该函数,就把它的申明提到头文件里去,否则 cpp 外部申明需加上 static 润饰; 1.4 类的动态成员对一个类中成员变量和成员函数来说,加了 static 关键字,则此变量/函数就没有 this指针了,必须通过类名拜访。 在类中,动态成员能够实现多个对象之间的数据共享,并且应用静态数据成员还不会毁坏暗藏的准则,即保障了安全性。因而,动态成员是类的所有对象中共享的成员,而不是某个对象的成员。对多个对象来说,静态数据成员只存储一处,供所有对象共用。 1.5 类的动态函数动态成员函数和静态数据成员一样,它们都属于类的动态成员,它们都不是对象成员。因而,对动态成员的援用不须要用对象名。在动态成员函数的实现中不能间接援用类中阐明的非动态成员,能够援用类中阐明的动态成员(这点十分重要)。如果动态成员函数中要援用非动态成员时,可通过对象来援用。从中可看出,调用动态成员函数应用如下格局:<类名>::<动态成员函数名>(<参数表>); 2 C++和C的区别2.1 设计思维上C++是面向对象的语言,而 C 是面向过程的结构化编程语言 2.2 语法上C++具备重载、继承、多态三种个性;C++相比 C,减少多许多类型平安的性能,比方强制类型转换;C++反对范式编程,比方模板类、函数模板等。 3 C++中四种cast转换C++中四种类型转换是:static_cast, dynamic_cast, const_cast, reinterpret_cast 3.1 const_cast用于将 const 变量转为非 const。它也是四个强制类型转换运算符中惟一可能去除 const 属性的运算符。对于未定义 const 版本的成员函数,咱们通常须要应用 const_cast 来去除 const援用对象的 const,实现函数调用。另外一种应用形式,联合 static_cast,能够在非 const 版本的成员函数内增加 const,调用完 const 版本的成员函数后,再应用 const_cast 去除 const限定。 ...

August 8, 2022 · 6 min · jiezi

关于c++:C多态

什么是多态多态是指调用同一个函数时,呈现不同的成果。多态分类动态的多态:函数重载就是动态的多态动静的多态:用父类的指针或援用调用虚函数虚函数虚函数是指:类的成员函数被 virtual 润饰的函数(一般函数不能用virtual润饰)留神: 内联函数理论是没有地址的,然而如果内联函数被virtual润饰,则编译器会疏忽函数的内联属性,把它当做失常函数应用。动态成员函数是不能作为虚函数的,因为动态函数调用时不会隐式传入this指针,所以动态成员函数无奈放入虚函数表。构造函数不能是虚函数,因为构造函数阶段,虚表还没有初始化,所以构造函数不能是虚函数。有虚函数的类,编译器会主动减少一个成员变量(虚表指针,指向虚表(函数指针数组)) 例如下列类,sizeof(A) == 12理论的成员变量为:1个指针类型,一个int类型,一个char类型依据对齐规定,所以类的大小为 12 字节。class A{public: virtual void test() //这个就是虚函数 {} int a; char b;}继承中形成多态的条件必须通过父类的指针或援用调用虚函数被调用的函数必须是虚函数,且子类必须对虚函数进行笼罩。 留神:虚函数的笼罩,必须是返回类型、函数名、参数列表都雷同才行。如果返回值是父类、子类的指针或援用时,返回值不同也能够形成虚函数笼罩(协变)如果父类的析构函数为虚函数,则子类的析构函数只有定义(无论是否virtual润饰),都与父类的虚析构函数形成笼罩。(析构函数自身函数名就不雷同)class A{public: virtual void test() //这个就是虚函数 {}}class B{ public: virtual void test() //笼罩父类的虚函数 {} }虚函数的重写(笼罩)子类会继承父类的虚函数,如果子类有父类虚函数的重写时,就会将重写的虚函数地址笼罩父类虚函数的地址。 留神:虚函数的重写,是从新实现父类的虚函数,所以重写的函数参数要应用父类的参数。下列代码运行后果为:B->0class A{public: virtual void test1(int a = 0) { cout << "A->" << a << endl; } virtual void test() //父类函数被子类调用 { test1(); //这里其实隐含了一个this,即this->test1() //子类调用test,传递指针p,所以这里是 p->test1() } };class B :public A{public: virtual void test1(int a = 1) { cout << "B->" << a << endl; //实践上这里应该是输入B->1 //然而这个函数重写父类的函数,是实现父类的函数 //所以a在这里要应用父类的a = 0 }};int main(){ B* p = new B; //创立子类 p->test(); //子类调用父类成员 return 0;}虚析构函数的笼罩下列 类A 的析构函数被申明为虚函数,子类的析构函数与父类形成笼罩class A{public: virtual ~A() //父类的析构函数申明为虚函数 { cout << "~A" << endl; }};class B :public A{public: ~B() //与父类的虚析构函数形成笼罩 { cout << "~B" << endl; }};int main(){ A* p1 = new A; A* p2 = new B; delete p1; delete p2; return 0;}形成笼罩后,delete p2时,会先调用子类的析构函数,再调用父类的析构函数。如果没有形成笼罩,则delete p2时只会调用父类的析构函数。关键字final和overridefinal:润饰虚函数,使虚函数不能被笼罩。(加在父类中) ...

August 3, 2022 · 2 min · jiezi

关于c++:QT-C类成员函数如何作为回调函数

在c++里,当设计一个底层类的时候,上游不晓得上游具体的类是什么,又须要调上游的办法(比方通过通信获取到了数据,须要将数据回传到上游),解决办法是将上游类的成员函数(其余函数同理)充当回调函数,传递给上游。 上游类:mainwindow #ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>class ServerProvider;QT_BEGIN_NAMESPACEnamespace Ui {class MainWindow;}QT_END_NAMESPACEclass MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow() override; void getData(const QString &str); private: Ui::MainWindow *ui; ServerProvider *m_serverProvider;};#endif // MAINWINDOW_H#include "mainwindow.h"#include <functional>#include "serverprovider.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); FuncDef func; func = std::bind(&MainWindow::getData, this, std::placeholders::_1); m_serverProvider = new ServerProvider(); m_serverProvider->setFunc(func);}MainWindow::~MainWindow() { delete ui; }void MainWindow::getData(const QString &str) { qDebug() << "GET DATA: " << str;}上游类:serverprovider ...

August 3, 2022 · 1 min · jiezi

关于c++:设备码打印量产工具

源代码 目标设施码量产工具实现了从手持扫码枪(一维码、二维码)到设施码生成再到设施标签贴纸打印的自动化 其中设施码生成规定反对 lua 脚本自定义,可实用于更多场景 留神仅反对 win 零碎,以后已测试 win10 及以上版本对于扫码枪,硬件需应用 USB-KBW 接口对于标签打印机 (以后标签排版尺寸,60mm x 40mm) 须在控制面板中可看到待应用的打印机需将待使应用的打印机设置为默认打印机 *对于编码转换规则:程序会应用扫码枪或手动输出的原始值通过 LUA 自定义转换规则生成最终的设施码 规定转换文件 numconv.lua 在装置目录下可见返回 ”“ 示意谬误 装置双击 设施码量产工具_setup.exe 点击 下一步(可选的更换装置门路)![4.png](/img/bVc1i8j 点击 下一步 点击 装置 点击实现 应用双击快捷图标 设施码量产工具 点击 OK 保障桌面焦点始终处于 设施码量产工具 最下面的文本输入框 (可看到光标闪动) 启动形式扫码枪扫码失去一次数值手动编辑数值到 最下面的文本输入框,按下回车 数据操作,点击 导出本次 按钮,将导出自程序关上后所有无效的设施编码值(.csv) 留神需依照理论应用的打印机与标签纸设置对应的打印参数 (ZEBRA-ZD888 为例)

July 25, 2022 · 1 min · jiezi

关于c++:编辑中

Qt 文章汇总基于百问网 IMX6ULL 的综合性桌面零碎 - DBoSNotepad 实例开发简略考勤自定义组件合集简略录音,一个简略的小帮手视频播放器Qss 根底材料整顿手写体辨认opencv调用摄像头的简略利用基于TCP的网络聊天室SM4 加解密客户端MQTT 客户端自定义登录对话框繁难计算器程序设计虹软人脸识别SDK应用100ASK_IMX6ULL_PRO开发板QT移植过程阐明QTcpServer 多线程解决框架

July 22, 2022 · 1 min · jiezi

关于c++:OneFlow源码阅读6自动微分机制

深度学习框架个别通过主动微分(autograd)机制计算梯度并反向流传。本文尝试通过一个简略的例子、浅显地察看一下OneFlow的autograd的实现机制。OneFlow刚刚曾经公布了v0.8.0。这个文档仍是基于v0.7.0的代码。 1 主动微分根底主动微分相干的材料比拟多,个人感觉主动微分的原理介绍这个系列及其援用的材料对相干背景常识的介绍比拟残缺清晰。上面分几种状况对梯度流传的原理做一些直观解释。 1.1 stack网络的梯度流传以x -> f -> g -> z这个stack网络为例,依据链式法则: ∂z/∂x = ∂z/∂g * ∂g/∂f * ∂f/∂x理论运行时,在梯度反向流传过程中: z将∂z/∂g传给g。如果节点g有权重w须要计算梯度,就计算∂z/∂w = ∂z/∂g * ∂g/∂w。g须要计算∂g/∂f,再乘以z传过来的梯度,将后果传给f。g只须要给f传递链式乘积的后果,不须要传递各项明细。在训练阶段的前向计算时,g须要保留∂g/∂f计算依赖的两头后果、以供反向计算时应用。其它节点的流传状况顺次类推。1.2 简略graph的梯度流传以上面这个简略的graph拓扑为例。 在持续之前,须要理解一下多元复合函数微分的根本公式。下图中,u和v都是对于x和y的函数,z是对于u和v的函数。依据这个公式能够晓得,z对x的梯度别离沿两条链路流传,z -> u -> x和z -> v -> x,节点x将两个梯度之和作为z对x的梯度。 1.3 简单graph的梯度流传再看一个拓扑略微简单点的例子: 上图能够视为x -> U -> L,其中U是e -> ... -> h的子图。f -> g的子图能够视为V。对于节点h来说,它须要把梯度传给g和k。对节点e来说,它须要对f和k传来的梯度求和,才是∂L/∂e。这样,L对x的梯度,仍能够按链路拆解,一条链路前后节点间的梯度是乘积关系,传入的多条链路梯度是加和关系。 这篇blog中有一个简直一样的拓扑图,给出了局部权重参数的梯度公式。 2 autograd中tensor相干的一些基本概念2.1 叶子节点OneFlow的autograd文档中介绍了leaf node和root node的概念。只有输入、没有输出的是leaf node,只有输出、没有输入的是root node。集体了解,如果把weight、bias、data视为计算图的一部分,这些节点就是叶子节点(op不是叶子节点)。尤其是从反向计算图的视角看,这些节点的grad_fn是空,反向流传到这些节点就会进行。 is_leaf和requires_grad有比拟亲密的关系,但二者又是独立的。PyTorch是这样解释的: requires_grad=false的节点都是叶子节点。比方data。requires_grad=true的节点如果是用户创立的,也是叶子节点。比方weight和bias。在梯度的反向计算过程中,只有叶子节点的梯度才会被填充。对于非叶子节点,如果要填充梯度信息,须要显式设置retain_grad=true。requires_grad=true才会计算、填充梯度。比方y = relu(x),y是op创立的、不是叶子节点。但如果x须要计算梯度,则y.requires_grad==true。但不须要为y填充梯度。对于叶子节点这个概念,目前找到的次要是直观形容,还没看到严格、清晰的定义。也可能是因为用户个别不会间接应用is_leaf,这个概念只是在浏览代码的时候才会波及到。上面的材料能够供进一步参考: What is the purpose of is_leaf?叶子节点和tensor的requires_grad参数2.2 tensor detachTensor的detach办法会创立一个新的tensor。新tensor的属性中 requires_grad = falseis_leaf = truedetach的意思是从grad的反向计算图中把tensor分离出来。新的tensor与原来的对象共享存储,但不参加反向图的拓扑结构。原有对象的requires_grad属性不变。比方上面的代码,批改一个对象的数据,另一个对象的数据也会扭转。 ...

July 20, 2022 · 2 min · jiezi

关于c++:C继承

继承继承是类中成员的复用。有元关系无奈被继承。继承的定义和应用办法下列父类成员 pri 为private,所以子类无法访问。其余成员子类皆可拜访。下列子类以protected 形式继承父类,所以子类的对象对父类的拜访权限最高为protected。父类中成员函数 Print() 为public,然而子类继承形式为 protected,所以子类对象对 Print()的拜访权限为 protected,无法访问。class Person //父类{public: void Print() { cout << "name:" << _name << endl; cout << "age:" << _age << endl; }protected: string _name = "bjf"; int _age = 18; private: int pri = 5;};class Student :protected Person //继承Person类,子类 public: void test() { cout << _name << endl; cout << _age << endl; Print(); }private: int code;};int main(){ Student xiaoming; xiaoming.test(); return 0;}继承形式只决定子类的对象对父类成员的最高拜访权限(最低权限取决于成员自身的权限),不影响子类对父类的拜访权限。子类能够拜访父类的所有成员,除了公有成员(只是不能拜访公有成员,然而子类依然继承了的)class默认的继承形式是private,struct默认继承形式是pubilc。类对象间的赋值规定能够将子类对象赋值给父类对象。(父类对象不能赋值子类对象)int main(){ Student bjf; Person man; man = bjf; //用子类对象赋值父类的对象,只将子类中继承的父类成员赋值过来,而子类本人的成员不论 Person* woman = &bjf; //woman指针,只代表bjf中的父类成员。 return 0;}继承中的作用域(对于暗藏)在继承的体系中,父类和子类有独立的作用域。如果父类和子类有同名成员,则须要表明该成员属于哪个类,否则会依据就近准则默认是子类的成员。(子类成员屏蔽了父类成员的间接拜访,这就是暗藏)留神:如果是同名成员函数,这个也是暗藏,须要指明属于哪个类(这个不是函数重载)class Person{public: int mun = 10;};class Student :public Person //继承Person类 {public: void test() { cout << mun << endl; //输入为 5,就近准则 cout << Person::mun << endl; //输入为 10 } int mun = 5;};int main(){ Student xiaoming; xiaoming.test(); return 0;}父类成员变量的初始化子类对父类成员变量的初始化,必须调用父类的构造函数进行初始化。留神: ...

July 19, 2022 · 1 min · jiezi

关于c++:C输入输出流IO流

输入输出过程 输入输出缓冲区的作用能够屏蔽低级IO的实现,低级IO的实现依赖操作系统自身,所以如果可能屏蔽这部分的差别,能够很容易写出可移植程序。cin从控制台读取数据时,空格示意将数据存储在不同的缓冲区(一个cin有一个缓冲区)string a;cin >> a; //输出 aa bb (两头有空格)cout << a << endl; //输入aa,输入第一个缓冲区的内容string a;cin >> a; //输出 aa bb (两头有空格)cout << a << endl; //输入aa,输入第一个缓冲区的内容cin >> a; //第二个缓冲区,在下面输出aa bb按回车后,就不会再次进行输出了cout << a << endl; //输入bb,第二个缓冲区内容。想要获取空格符,能够应用 getline()文件IO流<fstream>ifstream读文件explicit ifstream (const char* filename, ios_base::openmode mode = ios_base::in);filename :文件名(如果文件不存在,零碎不会主动创立文件,读取失败,零碎也不会报错)mode :操作文件的模式,默认为读文件ofstream写文件explicit ofstream (const char* filename, ios_base::openmode mode = ios_base::out);filename :文件名(如果文件不存在,则会主动创立一个文件)mode :操作文件的模式,默认为读文件上面的 >> 、 <<的文件操作形式是C++独有的,C没有。int main(){ ofstream ofs; string arr1 = "abcdef"; string arr2 = "192.168"; ofs.open("text.text", std::ofstream::out); //以写的模式关上文件 ofs << arr1 << " " << arr2; //向text.text文件中写入数据 ofs.close(); //敞开文件 ifstream ifs("text.text"); //以读的模式关上文件 ifs >> arr1 >> arr2; //读取8个字符,保留在arr中。 cout << arr1 << endl; cout << arr2 << endl; return 0;} ...

July 19, 2022 · 1 min · jiezi

关于c++:C模板

泛型编程泛型编程是指:应用一个非凡的类型(泛型)来定义变量,写一个模板函数,以适应传递不同类型的参数,下列的 T1 和 T2 就是一种泛型。 template <class T1,class T2>留神:模板不反对拆散编译,即申明在 .h 文件,定义在 .cpp 文件。然而能够在.h文件中定义,而后在蕴含这个h头文件的 .cpp 文件中利用。一般函数在编译时函数名会被编译称特殊符号。 int add(int a,int b); //编译时会被编译成 _Z4addii(?)而函数模板在编译阶段基本不会被编译为特殊符号,因为它没有实例化。所以在链接时,依据_Z4addii这个名字会找不到对应的函数原型。函数模板申明办法:template <class T> 示意将 T 申明为一种变量类型(泛型)依据传入的参数类型,T能够主动匹配对应的类型。这样就能够使一个函数能够用于不同变量类型中,减少函数的复用,这就是函数模板。不同中央调用函数模板时,调用的不是同一个函数,尽管都是同一个模板编译器在这里,将模板依据实参类型进行了实例化,实例化成不同的函数。留神:如果存在非模板函数的同名函数,如果条件雷同的状况下,则会优先调用非模板函数。template <class T1,class T2>T1 ADD(T1& x1, T2& x2){ return x1+x2;}int main(){ int a1 = 10, b1 = 20; char a2 = 5, b2 = 10; ADD(a1, b1); //这个与上面这个都是调用的Swap函数 ADD(a1, a2); //然而调用的不是同一个函数 cout << "a1 = " << a1 << " b1 = " << b1 << endl; cout << "a2 = " << a2 << " b2 = " << b2 << endl; return 0;} ...

July 19, 2022 · 1 min · jiezi

关于c++:C内存管理

内存分类栈区、堆区、动态区、代码段 栈区 :用来存储局部变量、函数的形式参数(寄存长期变量)堆区 :动态内存调配动态区 :寄存动态变量、全局变量(程序完结时,才被销毁)代码段 :寄存函数体(类成员函数和全局函数)的二进制代码int globalvar = 10; //globalvar 存储于动态区(数据段)static int stglobalvar = 10; //stglobalvar 存储于动态区int main(){ static int stcavar = 10; //stcavar 存储于动态区 int locavar = 10; //locavar 局部变量,存储于栈 int num1[10] = { 1,2,3,4 }; //num1 数组存储于栈 char char2[] = "abcd"; //char2 存储于栈; *char2 存储于栈 const char* pchar3 = "abcd"; //pchar3 局部变量指针存储于栈中,*pchar3 存储于代码段中(常量区) int* ptr = (int*)malloc(sizeof(int) * 4); //ptr 局部变量指针存储于栈中; *ptr开拓的空间,存储于堆中 free(ptr);}内存透露什么是内存透露:因为某种原因导致程序未能开释不再应用的内存。内存透露不是指物理上的内存隐没,而是指失去了对某段内存的控制权(指针失落)C++动静申请内存newC++语法兼容C语言,所以C语言的malloc和realloc等都能够应用。C++语法还有新的办法能够动静申请内存空间——new和delete留神:malloc开拓的空间只能free,new开拓的空间只能delete。int main(){ int* ptr1 = (int*)malloc(sizeof(int) * 4); int* ptr2 = new int[10]; //开拓多个空间时,应用中括号 free(ptr1); delete[] ptr2; int* ptr3 = (int*)malloc(sizeof(int)); int* ptr4 = new int; //开拓单个空间时 free(ptr3); delete ptr4;}malloc和new的区别malloc和new在申请根本类型的空间时,都是一样的,没有区别。区别: ...

July 15, 2022 · 2 min · jiezi

关于c++:C-自定义二叉树并输出二叉树图形

原文链接 应用C++构建一个二叉树并输入。 输出输出根节点为10,顺次输出6、4、8、14、12、16 代码如下: #include <stdio.h>#include <stdlib.h>#include <vector>#include<iostream>#include <stack> #include<cstdlib>#include <string>using namespace std;struct TreeLinkNode // 定义二叉树{ int val; // 以后节点值用val示意 struct TreeLinkNode *left; // 指向左子树的指针用left示意 struct TreeLinkNode *right; // 指向右子树的指针用right示意 struct TreeLinkNode *parent; //指向父节点的指针用parent示意 TreeLinkNode(int x) :val(x), left(NULL), right(NULL), parent(NULL) { } // 初始化以后结点值为x,左右子树、父节点为空};//创立树TreeLinkNode* insert(TreeLinkNode* tree, int value){ TreeLinkNode* node = (TreeLinkNode*)malloc(sizeof(TreeLinkNode)); // 创立一个节点 node->val = value; // 初始化节点 node->left = NULL; node->right = NULL; node->parent = NULL; TreeLinkNode* temp = tree; // 从树根开始 while (temp != NULL) { if (value < temp->val) // 小于根节点就进左子树 { if (temp->left == NULL) { temp->left = node; // 新插入的数为temp的左子树 node->parent = temp; // temp为新插入的数的父节点 return tree; } else // 下一轮判断 temp = temp->left; } else // 否则进右子树 { if (temp->right == NULL) { temp->right = node; // 新插入的数为temp的右子树 node->parent = temp; // temp为新插入的数的父节点 return tree; } else // 下一轮判断 temp = temp->right; } } return tree;} // ************* 输入图形二叉树 *************void output_impl(TreeLinkNode* n, bool left, string const& indent){ if (n->right) { output_impl(n->right, false, indent + (left ? "| " : " ")); } cout << indent; cout << (left ? '\\' : '/'); cout << "-----"; cout << n->val << endl; if (n->left) { output_impl(n->left, true, indent + (left ? " " : "| ")); }}void output(TreeLinkNode* root){ if (root->right) { output_impl(root->right, false, ""); } cout << root->val << endl; if (root->left) { output_impl(root->left, true, ""); } system("pause");}// ***************************************// ====================测试代码====================int main(){ TreeLinkNode tree = TreeLinkNode(10); // 树的根节点 TreeLinkNode* treeresult; treeresult = insert(&tree, 6); // 输出n个数并创立这个树 treeresult = insert(&tree, 4); treeresult = insert(&tree, 8); treeresult = insert(&tree, 14); treeresult = insert(&tree, 12); treeresult = insert(&tree, 16); output(treeresult); // 输入图形二叉树}输入 ...

July 15, 2022 · 2 min · jiezi

关于c++:C-构建并复制二叉树

原文链接 应用C++构建一个二叉树并复制、输入。 程序#include <stdio.h>#include <stdlib.h>//#include <cstdio>#include <vector>#include<iostream>#include <stack> #include<cstdlib>#include <string>using namespace std;struct TreeNode // 定义二叉树{ int val; // 以后节点值用val示意 struct TreeNode *left; // 指向左子树的指针用left示意 struct TreeNode *right; // 指向右子树的指针用right示意 TreeNode(int x) :val(x), left(NULL), right(NULL) { } // 初始化以后结点值为x,左右子树为空};//创立树TreeNode* insert(TreeNode* tree, int value){ TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); // 创立一个节点 node->val = value; // 初始化节点 // malloc函数能够调配长度 node->left = NULL; node->right = NULL; TreeNode* temp = tree; // 从树根开始 while (temp != NULL) { if (value < temp->val) // 小于根节点就进左子树 { if (temp->left == NULL) { temp->left = node; // 新插入的数为temp的左子树 return tree; } else // 下一轮判断 temp = temp->left; } else // 否则进右子树 { if (temp->right == NULL) { temp->right = node; // 新插入的数为temp的右子树 return tree; } else // 下一轮判断 temp = temp->right; } } return tree;} // ************* 输入图形二叉树 *************void output_impl(TreeNode* n, bool left, string const& indent){ if (n->right) { output_impl(n->right, false, indent + (left ? "| " : " ")); } cout << indent; cout << (left ? '\\' : '/'); cout << "-----"; cout << n->val << endl; if (n->left) { output_impl(n->left, true, indent + (left ? " " : "| ")); }}void output(TreeNode* root){ if (root->right) { output_impl(root->right, false, ""); } cout << root->val << endl; if (root->left) { output_impl(root->left, true, ""); } system("pause");}// ******************************************void CopyBiTree(TreeNode* root, TreeNode* newroot) // 复制二叉树{ if (root == nullptr) return; else { newroot->val = root->val; if (root->left != nullptr) newroot->left = new TreeNode(0); if (root->right != nullptr) newroot->right = new TreeNode(0); CopyBiTree(root->left, newroot->left); CopyBiTree(root->right, newroot->right); } //output(newroot);}// ====================测试代码====================int main(){ TreeNode* tree =new TreeNode(10); // 树的根节点 TreeNode* treeresult; treeresult = insert(tree, 6); // 输出n个数并创立这个树 treeresult = insert(tree, 4); treeresult = insert(tree, 8); treeresult = insert(tree, 14); treeresult = insert(tree, 12); treeresult = insert(tree, 16); TreeNode* mirroot = new TreeNode(10); CopyBiTree(treeresult, mirroot); // 复制二叉树 output(treeresult); // 输入原二叉树 output(mirroot); // 输入复制的二叉树}后果 ...

July 15, 2022 · 2 min · jiezi

关于c++:C-创建链表并输出

原文链接 应用C++代码创立一个链表并输入: #include <stdio.h>#include <stdlib.h>//#include <cstdio>//#include <vector>#include<iostream>#include<cstdlib>using namespace std;//定义一个构造体 ListNode的构造struct ListNode { int val; //以后结点的值用val示意 struct ListNode *next; //指向下一个结点的指针用next示意 ListNode(int x) : val(x), next(NULL) { } //初始化以后结点值为x,指针为空};void print(ListNode *head) //打印输出链表{ ListNode *p = head; while (p != NULL) { cout << p->val; p = p->next; }}ListNode* CreateListNode(ListNode* pHead) // 创立链表{ ListNode* p = pHead; // 申明挪动指针,最开始指向头结点 for (int i = 1; i < 10; ++i) { ListNode* pNewNode; // 申明链表 pNewNode 来保留数据,pNewNode 就是一个链表的节点 pNewNode = new ListNode(0); // 初始化变量 pNewNode pNewNode->val = i; // 将新节点的值赋值为 i pNewNode->next = NULL; p->next = pNewNode; // p的下一节点指向这个新的节点,将此节点与头节点连贯 p = pNewNode; // p节点指向这个新的节点,向后挪动指针,以便下一次链接;p始终指向链表最初的一个节点 } return pHead;}int main(){ ListNode* head; // 申明头节点 head = new ListNode(0); // 头节点须要赋值能力调用 ListNode* p = CreateListNode(head); // 援用头节点创立链表 print(p); //援用打印 system("pause");}学习更多编程常识,请关注我的公众号: ...

July 15, 2022 · 1 min · jiezi

关于c++:类和对象

类类由两局部组成:成员变量(属性)、成员函数(成员的行为)在类中定义的成员函数,编译器会默认成内联函数。C++中将 struct 降级为类的定义(同样可能定义构造体,兼容C语言)C++中还能够应用 class 来定义类,用法跟struct雷同。类的申明与实例化struct People //还能够写为class People{public: //示意下列的都是私有的 void Init() //类中能够定义函数,构造体不行 { int a = 10; //Init函数在类的外部创立作用域,所以这里Init函数是定义 } void Push(); //Push函数是在里面定义的,这里只是申明(申明和定义拆散) int _a; //这里的成员变量都是申明,不是定义,在内存中开拓空间时能力称为定义。 char _b; struct People* _ptr;} void People:: Push(){ int a = 10;}int main(){ People man; //类的实例化}类的拜访限定符public :私有protected :爱护private :公有拜访限定符的作用范畴:以后拜访限定符的地位到下一个拜访限定符的地位,或者类完结。如果没有增加拜访限定符,class默认状况下是公有的,struct默认状况下是私有的。类的大小类中的函数被寄存在公共区域中(代码段)所以类的大小只思考成员变量的大小,不思考成员函数的大小。留神:思考成员变量大小时,遵循构造体的对齐规定。空类的大小为 1 ,给一个字节是为了占位,用来示意对象存在。class People{ char _b; int _a; short _c; void init() { }}int main(){ People man; cout << sizeof(man) << endl; //输入后果为 12 }面向对象的三大个性封装:将数据和操作数据的办法进行有机联合,暗藏对象的属性和实现细节,仅对外公开接口来和对象进行替换(其本质是一种治理)继承多态this指针在定义两个对象 today 和 tommor 时,调用 Init 函数,他们调用的是同一个函数。然而,这时 _year 等的成员变量就不好辨别到底是 today 的还是是 tommor 的。所以编译器就减少了一个隐含的参数 ...

July 11, 2022 · 4 min · jiezi

关于c++:C20-以-Bazel-Clang-开始

C++20 如何以 Bazel & Clang 进行构建呢? 本文将介绍: Bazel 构建零碎的装置LLVM 编译系统的装置 Clang is an "LLVM native" C/C++/Objective-C compilerBazel Clang 工具链的配置C++20 库与利用的构建本文示例可见: https://github.com/ikuokuo/st... 本文是于 Ubuntu 20 上进行的实际,Windows 能够用 WSL 筹备环境。 装置 Bazel,以二进制形式Bazelisk 是装置 Bazel 的举荐形式,咱们装置它的二进制公布即可: cd ~wget https://github.com/bazelbuild/bazelisk/releases/download/v1.12.0/bazelisk-linux-amd64 -O bazelisk-1.12.0-linux-amd64chmod a+x bazelisk-*sudo ln -s $(pwd)/bazelisk-1.12.0-linux-amd64 /usr/local/bin/bazeltouch WORKSPACE# 国内下载 Bazel 可能遇到如下问题,配置 .bazeliskrc 解决# could not resolve the version 'latest' to an actual version number# https://github.com/bazelbuild/bazelisk/issues/220cat <<-EOF > .bazeliskrcBAZELISK_BASE_URL=https://github.com/bazelbuild/bazel/releases/downloadUSE_BAZEL_VERSION=5.2.0EOFbazel version更多形式,可见官网文档。进一步,举荐装置 buildtools,下载后软链一下: sudo ln -s $(pwd)/buildifier-5.1.0-linux-amd64 /usr/local/bin/buildifiersudo ln -s $(pwd)/buildozer-5.1.0-linux-amd64 /usr/local/bin/buildozerBazel 如何构建 C++ 我的项目,可见我的 Start Bazel 笔记。 ...

July 11, 2022 · 4 min · jiezi

关于c++:C入门

命名空间namespacenamespace :命名空间,相当于定义了一个作用域,用来解决命名抵触问题。域作用限定符:拜访命名空间中的内容,应用双冒号 : : ,当: :右边为空时,示意应用全局域。// 定义第一个命名空间namespace first_space{ void func(){ int a = 1; cout << "Inside first_space" << endl; }}// 定义第二个命名空间namespace second_space{ void func(){ int a = 2; cout << "Inside second_space" << endl; }}int a = 10;int main (){ int a = 5; printf("%d\n",a); //a = 5 ,就近准则,应用a = 5的那个。 printf("%d\n",first_space::a); //a = 1 printf("%d\n",::a); //a = 10,::右边为空,代表应用全局域(全局变量) // 调用第一个命名空间中的函数 first_space::func(); // 调用第二个命名空间中的函数 second_space::func(); return 0;}using :using namespace 指令,这个指令会通知编译器,后续的代码将应用指定的命名空间中的名称,这样在应用命名空间时就能够不必在后面加上命名空间的名称。using namespace first_space;int main (){ // 调用第一个命名空间中的函数 func(); return 0;}嵌套命名空间,能够应用: :来拜访嵌套的命名空间。namespace namespace_name1 { // 代码申明 namespace namespace_name2 { // 代码申明 }}// 拜访 namespace_name2 中的成员using namespace namespace_name1::namespace_name2; // 拜访 namespace_name1 中的成员using namespace namespace_name1;C++库为了避免命名抵触,将本人库中的货色都定义在一个 std 的命名空间中所以有时候程序中都会调用 using namespace std; 这个库。#include <iostream> //援用.h头文件,为了与老版辨别,在新版中不必写.husing namespace std; //调用std库int main(){ cout << "hello world" << endl; //因为下面写了using,所以能够不写命名空间 std::cout << "hello world" << std::endl; //指定命名空间 return 0;}C++输出和输入C++的输入输出能够自动识别类型,不必手动表明。 ...

July 8, 2022 · 3 min · jiezi

关于c++:AddressSanitizer-技术初体验

简介 AddressSanitizer 是 Google 开发的一款用于检测内存拜访谬误的工具,用于解决 use-after-free 和内存透露的相干问题。它内置在 GCC 版本 >= 4.8 中,实用于 C 和 C++ 代码。AddressSanitizer 可在应用运行时检测跟踪内存调配,这意味着必须应用 AddressSanitizer 构建代码能力利用它的性能。 因为内存透露会减少程序应用的总内存,所以当不再须要内存时,正确开释内存很重要。或者对于小程序,失落几个字节仿佛没什么大不了的,然而对于应用大量内存的长时间运行的程序,防止内存透露变得越来越重要。如果程序不再须要它时,无奈开释应用的内存,很可能会耗尽内存,从而导致应用程序提前终止。AddressSanitizer 的呈现,就能够帮忙检测这些内存透露。 此外,AddressSanitizer 能够检测 use-after-free 谬误。当程序尝试读取或写入已被开释的内存时,会产生开释后应用谬误。这是未定义的行为,可能会导致数据损坏、后果不正确,甚至程序解体。 如果检测到谬误,程序将向 stderr 打印谬误音讯,并以非零退出代码退出,若是应用 AddressSanitizer,那么它在第一个检测到的谬误时就退出。 留神 ASan 应用本人的内存分配器(malloc, free 等)ASan 应用大量虚拟地址空间(x86_64 Linux 上为 20T) 应用 -fsanitize=address 标记用于通知编译器,将增加 AddressSanitizer,对应用调试符号编译代码很有帮忙。如果存在调试符号,须要 AddressSanitizer 打印行号,那么请增加 -g 标记。此外,如果您发现堆栈跟踪看起来不太正确,应用 -fno-omit-frame-pointer 就能够显示更具体的调用栈信息,合并成一条命令生成可执行文件: gcc main.cpp -o main -g -fsanitize=address此段代码为 Bash 或者,分成独自的编译和链接阶段: gcc -c main.cpp -fsanitize=address -g` -fno-omit-frame-pointergcc main.o -o main -fsanitize=address此段代码为 Bash 请留神,编译和链接步骤都须要 -fsanitize=address 标记。如果构建零碎更简单,将这些标记放在 CXXFLAGS 和 LDFLAGS 环境变量中。 ...

July 6, 2022 · 5 min · jiezi

关于c++:VS2022-win10编译SFML26

之前写过一篇Clion配置C++/SFML开发环境(Win10),因为Clion是免费的IDE,收费的IDE目前靠谱的抉择只有Visual Studio,因而再写一篇基于Visual Studio 2022的教程。因为SFML未提供编译好的基于Visual Studio 2022的版本,因而这里须要本人编译。 环境操作系统: windows 10 版本 1909 (外部版本 18363.1646)IDE: Microsoft Visual Studio Community 2022 (64 位) 版本 17.2.5CMake: cmake-gui 3.24.0-rc2SFML: 2.6.x (Github源码编译)步骤从Github下载2.6.x分支的SFML源码关上CMake-gui,如图所示,抉择下载好SFML源代码目录,任意设置一个build目录,而后点击Configure 抉择Visual Studio 2022作为generator,点击Finish 此时Configure开始执行,执行完(Configuring done)成会呈现红色的参数须要设置,如下图所示,个别都不必改,我这里把CMAKE_INSTALL_PREFIX改成另一个指定的目录,而后再次点击Configure 第二次Configure实现之后,不再有红色参数,点击旁边的Generate,执行实现后,点击Open Project 此时会关上Visual Studio 2022,执行INSTALL -> 生成,即可把SFML装置在指定的目录。 通过Visual Studio 2022再新建一个CMake我的项目,CMakeLists.txt内容如下 cmake_minimum_required (VERSION 3.8) project("SFML2048") # 设置SFML目录 set(SFML_DIR "D:\\Program Files\\SFML\\lib\\cmake\\SFML") find_package(SFML REQUIRED COMPONENTS audio network graphics window system) if (NOT SFML_FOUND) message(FATAL_ERROR "SFML NOT FOUND!") else() message("SFML FOUND!") endif() include_directories(${SFML_INCLUDE_DIR}) add_executable (SFML2048 "SFML2048.cpp" "SFML2048.h") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET SFML2048 PROPERTY CXX_STANDARD 20) endif() target_link_libraries("SFML2048" sfml-main sfml-audio sfml-network sfml-graphics sfml-window sfml-system) # 把DLL复制到执行目录 set( DLL_FILES "D:\\Program Files\\SFML\\bin\\sfml-graphics-2.dll" "D:\\Program Files\\SFML\\bin\\sfml-window-2.dll" "D:\\Program Files\\SFML\\bin\\sfml-system-2.dll" ) foreach(DLL_FILE ${DLL_FILES}) message("Found DLL to Copy: ${DLL_FILE}") add_custom_command( TARGET SFML2048 PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DLL_FILE} ${CMAKE_BINARY_DIR}. ) endforeach()测试以下代码,执行胜利将绘制一个绿色的圆 ...

June 29, 2022 · 1 min · jiezi

关于c++:C-explicit-用法

引言本文介绍了 C++ 中 explicit 关键字的用法. 原文地址: C++ explicit 用法 欢送拜访我的博客: http://blog.duhbb.com/ explicit 作用在 C++中, explicit 关键字用来润饰类的构造函数, 被润饰的构造函数的类, 不能产生相应的隐式类型转换, 只能以显式的形式进行类型转换. explicit 应用注意事项: explicit 关键字只能用于类外部的构造函数申明上.explicit 关键字作用于单个参数的构造函数 (多个参数也实用, 但必须只有一个参数须要赋值, 其余的参数有默认值).在 C++ 中, explicit 关键字用来润饰类的构造函数, 被润饰的构造函数的类, 不能产生相应的隐式类型转换.it cannot be used for implicit conversions and copy-initialization多个参数的状况其实对于下面的第二点我是存疑的, 因为 CPP Reference explicit specifier 中的例子表明 explicit 是能够用于多个参数的. 例子例 1 根底例子#include <bits/stdc++.h>using namespace std;class Test1 {public: Test1(int n) { m_num = n; }private: int m_num;};class Test2 {public: explicit Test2(int n) { m_num = n; }private: int m_num;};int main() { Test1 t1 = 12; // 隐式调用构造函数胜利 Test2 t2 = 12; // 编译谬误, 不能隐式调用其构造函数 Test2 t2(12); // 显式调用胜利 return 0;}例 2 CPP Reference 中的例子上面是 CPP Reference explicit specifier 中的例子, 感觉更全面一点: ...

June 28, 2022 · 2 min · jiezi

关于c++:C头文件-bitsstdch-是啥

原文地址: 【C++】头文件 bits/stdc++.h 是啥? 欢送拜访我的博客:http://blog.duhbb.com/ 嘿嘿, 当前写 leetcode 的话, 本地间接就援用这个文件, 还是很不便的;然而因为不可移植以减少编译工夫等, 墙裂倡议不要在生产环境应用. 引言最近看他人的 C++ 代码, 发现了这么一个头文件: #include <bits/stdc++.h>而后我就有点奇怪了, 以前如同没有遇到过呀, 而后这个 C++ 头文件也比拟特地, 是以 .h 结尾的, 于是乎打算一探到底. 它是 C++ 中反对的一个简直万能的头文件, 简直蕴含所有的可用到的 C++ 库函数. 当前写代码就能够间接援用这一个头文件了, 不须要在写一大堆 vector, string, map, stack 等等 应用办法#include <bits/stdc++.h>int main() { // write code here return 0}头文件的内容// C++ includes used for precompiling -*- C++ -*-// Copyright (C) 2003-2013 Free Software Foundation, Inc.//// This file is part of the GNU ISO C++ Library. This library is free// software; you can redistribute it and/or modify it under the// terms of the GNU General Public License as published by the// Free Software Foundation; either version 3, or (at your option)// any later version.// This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// Under Section 7 of GPL version 3, you are granted additional// permissions described in the GCC Runtime Library Exception, version// 3.1, as published by the Free Software Foundation.// You should have received a copy of the GNU General Public License and// a copy of the GCC Runtime Library Exception along with this program;// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see// <Licenses - GNU Project - Free Software Foundation>./** @file stdc++.h * This is an implementation file for a precompiled header. */// 17.4.1.2 Headers// C#ifndef _GLIBCXX_NO_ASSERT#include <cassert>#endif#include <cctype>#include <cerrno>#include <cfloat>#include <ciso646>#include <climits>#include <clocale>#include <cmath>#include <csetjmp>#include <csignal>#include <cstdarg>#include <cstddef>#include <cstdio>#include <cstdlib>#include <cstring>#include <ctime>#if __cplusplus >= 201103L#include <ccomplex>#include <cfenv>#include <cinttypes>#include <cstdalign>#include <cstdbool>#include <cstdint>#include <ctgmath>#include <cwchar>#include <cwctype>#endif// C++#include <algorithm>#include <bitset>#include <complex>#include <deque>#include <exception>#include <fstream>#include <functional>#include <iomanip>#include <ios>#include <iosfwd>#include <iostream>#include <istream>#include <iterator>#include <limits>#include <list>#include <locale>#include <map>#include <memory>#include <new>#include <numeric>#include <ostream>#include <queue>#include <set>#include <sstream>#include <stack>#include <stdexcept>#include <streambuf>#include <string>#include <typeinfo>#include <utility>#include <valarray>#include <vector>#if __cplusplus >= 201103L#include <array>#include <atomic>#include <chrono>#include <condition_variable>#include <forward_list>#include <future>#include <initializer_list>#include <mutex>#include <random>#include <ratio>#include <regex>#include <scoped_allocator>#include <system_error>#include <thread>#include <tuple>#include <typeindex>#include <type_traits>#include <unordered_map>#include <unordered_set>#endif长处与毛病起源: bits/stdc++.h in C++ ...

June 27, 2022 · 2 min · jiezi

关于c++:C-静态反射在网易云信-SDK-中的实践

对话零碎目前网易云信 IM SDK 反对全平台,IM SDK 每次发版除了要针对新性能进行测试外,回归测试也占了很大比重,随着 IM SDK 反对的平台越来越多,API 接口越来越丰盛,每次须要回归测试的范畴也在一直减少,如果以人工来实现,不仅效率低下,而且可能会产生漏测、误判等问题。为了进步回归效率、继续监控程序品质,云信在“品质保障体系”建设中投入了大量精力来搭建和欠缺“自动化测试平台”,“API 自动化测试”作为自动化测试平台的重要组件,为“单元测试”、“回归测试”、“每日构建”等性能提供了无力撑持,接入自动化测试平台十分有意义,其中“API 自动化测试”的次要流程如下图所示,本文就“依据 API 信息转为 API 调用”、“API 调用后果转换为用例执行后果数据”在桌面端(Windows、MacOSX、Linux)实现的关键技术进行探讨。 为什么要应用反射下图所展现的内容是由“自动化测试平台”下发的用例信息(为了不便展现,字段有裁剪)。 其中 className、methodName 形容了 SDK-API 的 NIMAuthService::login 办法,params 结点则形容了 login 办法的参数,依据上节提到的“依据 API 信息转为 API 调用”、“API 调用后果转换为用例执行后果数据”,其中波及到转换有两种: API 转换依据用例传入的 className、methodName 来找到对应的 API。 从上图的数据上来看要找到 NIMAuthService::login 进行调用。 数据转换JsonData2cppStruct,测试平台 Json 数据转换到 C++ 数据。 cppStruct2JsonData,C++ 执行后果数据转换为 Json 数据上报到测试平台。 从上图的数据上来看要把 data 节点的数据转换为 NIMAuthInfo,做为 NIMAuthService::login 的调用参数. 对于这种场景应用“反射”无疑是最合适与优雅的形式,为什么这么说呢,能够进行如下的比照: IM SDK-API(仅示例): namespace nim {struct AuthInfo {std::string accid;std::string token;std::string appkey;}; struct AuthCallbackParam {std::string accid;bool result;int step;};using LoginCallback = std::function<void(const AuthCallbackParam&)>;struct NIMAuthService {static bool login(const AuthInfo& info) {std::cout << info.accid << " / " << info.token << " / " << info.appkey << std::endl;return true;}static void loginEx(const AuthInfo& info,const LoginCallback& callback) {std::cout << info.accid << " / " << info.token << " / " << info.appkey << std::endl;if (callback != nullptr) {callback(true);}}};}不应用反射机制,须要依据输出的 Json 数据来查找对应的 service,并找到对应的办法,把 Json 数据转换为对应的 C++ 构造,而后进行 API 调用,基中会波及到大量的反复逻辑的判断。 ...

June 16, 2022 · 8 min · jiezi

关于c++:通讯录管理系统的设计实现

一想到“管理系统”,咱们脑海里通常浮现四个字,增查删改。这也是必不可少的局部。我先把这个零碎我要实现的局部列举进去(当然,我的思路有很多有余,恳请大佬斧正,批评,不胜感激) cout << "***********1.增加联系人**********" << endl; cout << "***********2.显示联系人**********" << endl; cout << "***********3.删除联系人**********" << endl; cout << "***********4.查找联系人**********" << endl; cout << "***********5.批改联系人**********" << endl; cout << "***********6.清空联系人*********" << endl; cout << "***********0.退出零碎***********" << endl;(备注:退出也是其中一个性能哦) 首先,构建构造体变量 #define MAX 1000struct person{ string name; int sex{ }; int age{ }; string phonenumber; string address;};struct addressbook{ struct person personArr[MAX]; int person_size{ };增加联系人void addPerson(addressbook* aaa) //增加联系人模块{ if (aaa->person_size < MAX) { string name; cout << "请输出姓名:" << endl; cin >> name; aaa->personArr[aaa->person_size].name = name; int sex; cout << "请输出性别对应序号:(1--男 2--女)" << endl; while (true) { cin >> sex; if ((sex == 1) || (sex == 2)) { aaa->personArr[aaa->person_size].sex = sex; break; } else { cout << "您输出的有误,请查看后从新输出!" << endl; } } int age = 0; cout << "请输出年龄:" << endl; cin >> age; aaa->personArr[aaa->person_size].age = age; string phonenumber; cout << "请输出电话:" << endl; cin >> phonenumber; aaa->personArr[aaa->person_size].phonenumber = phonenumber; string address; cout << "请输出地址:" << endl; cin >> address; aaa->personArr[aaa->person_size].address = address; aaa->person_size++; cout << "增加联系人胜利!" << endl; } else { cout << "联系人已满,请删除局部联系人再增加!" << endl; } system("pause"); system("cls");}显示联系人void showperson(addressbook person){ if (person.person_size == 0) { cout << "联系人列表为空" << endl; } for (int i = 0; i < person.person_size; i++) { cout << i + 1 << "." << "姓名:" << person, personArr[i].name << " " << "性别:" << (person.personArr[i].sex == 1 ? "男":"女") << " " << "年龄:" << person.personArr[i].age << " " << "电话:" << person.personArr[i].phonenumber << " " << "住址:" << person.pearsonArr[i].address << " " << endl; } system("pause"); system("cls");}删除联系人void deleteperson(addressbook * person) ...

June 16, 2022 · 6 min · jiezi

关于c++:OneFlow源码阅读5Global-Tensor

OneFlow的官网文档中提供了一个结构global tensor的例子。结构时指定placement和sbp参数就是全局视角的global tensor,数据能够散布在多个节点上。在单机CPU环境下,能够启动3个过程、每个过程设置不同的环境变量,运行如下Python代码就能够创立一个简略的global tensor。 # export MASTER_ADDR=127.0.0.1 MASTER_PORT=17789 WORLD_SIZE=3 RANK=0 LOCAL_RANK=0# export MASTER_ADDR=127.0.0.1 MASTER_PORT=17789 WORLD_SIZE=3 RANK=1 LOCAL_RANK=1# export MASTER_ADDR=127.0.0.1 MASTER_PORT=17789 WORLD_SIZE=3 RANK=2 LOCAL_RANK=2import oneflow as flowP0 = flow.placement("cpu", ranks=[0, 1])a0_sbp = flow.sbp.split(0)A0 = flow.Tensor([[1,2,3],[4,5,6]], placement=P0, sbp=a0_sbp)1 sbpsbp由split, broadcast, partial的首字母组合而成。 split示意物理设施上的tensor,是将global tensor切分失去的。broadcast示意global tensor会复制并播送到所有的物理设施上。partial示意global tensor与物理设施上的tensor的形态雷同,然而物理设施上的值,只是global tensor的一部分。Python端flow.sbp包定义了split等3种类型。其C++ binding代码在sbp_symbol.cpp中。这些类型都是SbpParallel类型,是protobuf message对象。三种类型通过oneof parallel_type共享存储。 其中broadcast和partial_sum都是空音讯,赋值时须要调用mutable办法显式表明oneof字段具体是哪种类型。split的值示意在tensor的哪个轴上切分数据。轴的index值是一个[[0, 5]之间的整数](https://github.com/Oneflow-In...)。所有的split SbpParallel对象被保留到一个动态vector中。 2 placement的结构placement属性指定tensor寄存在哪些物理设施上。或者,在纯CPU环境下,tensor寄存在哪些过程中。在上述例子中,flow.placement("cpu", ranks=[0, 1])创立一个placement对象。第一个参数是设施类型,目前反对cpu或cuda。ranks示意设施列表,tensor将散布在这些设施上(依据sbp的批示切分或播送数据)。ranks只列出了rank id(全局惟一),没有指定节点host。rank与host关系是依据环境变量确定的。环境变量RANK示意全局惟一的rank id,LOCAL_RANK示意节点内的本地rank id。在GPU环境下,个别一个过程对应一块设施。WORLD_SIZE示意所有节点的设施(过程)总数。 oneflow包在初始化时,会依据环境变量在各个节点间建设管制面通信连贯,以及数据面通信连贯。这样每个过程就晓得有多少个节点、有多少个设施/过程、以后过程在整个集群的地位。 通过placement的构造函数绑定能够晓得,其对应的C++类型是ParallelDesc。对象结构由函数CreateParallelDescSymbol实现。次要调用流程如下: 2.1 确定machine和deviceParseAndFormatRanks会将ranks数组[0, 1]转为形如"machine_id:device_id"的字符串数组,供后续解决应用。这里的逻辑决定了如何依据ranks中的id,确定tensor数据在节点和设施上的散布: machine_id = rank / NumOfProcessPerNodedevice_id = rank % NumOfProcessPerNode从上述公式能够看出,各个节点的设施/过程数量须要是统一的。 ...

June 15, 2022 · 1 min · jiezi

关于c++:C出现cout不明确的问题的原因和解决方法

如果你有幸看到这个博客,那么我猜你应该曾经碰上这个问题,而且正急着寻求办法,因而,我先把解决办法用最简略的一句话写进去解决办法为:**将文件中原有的using namespace std;删除后保留cpp文件,再加上using namespace std;保留cpp文件。问题即可解决** 如果根据上述办法曾经解决了这个问题,感觉感兴趣,好奇怎么产生的这个问题,这里我大抵介绍下。 这个问题的知识点是namespace的用法:通过 namespace 关键字,能够申明命名空间,在命名空间内部须要通过齐全限定名拜访这些对象,通常状况下,申明的命名空间代码和调用的代码不在同一个文件里,因而在其余文件中应用,留神引入的门路要写正确,因而,呈现cout不明确的问题应该是门路不明确导致。 真挚的心愿这个简短的博客能够帮到遇到这个问题的敌人。

June 15, 2022 · 1 min · jiezi

关于c++:比特熊故事汇6月MVP英雄故事微软MVP-X-英特尔特邀专家一起消夏

夏日炎炎,吹着空调 共度一场直播时光 比特熊与新晋微软MVP和英特尔特邀嘉宾 带来全新技术主题和热门话题探讨 2022年6月17日(周五) 【比特熊故事汇】和你直播间相聚 比特熊消夏小礼物比特熊直播间心愿跟各位开发人和技术爱好者密切交换,大家能够通过直播互动和文章留言的形式一起参加!但凡转发本篇文章、在预报文章中踊跃发言或者参加直播弹幕互动的搭档,都有机会取得比特熊送出的小礼物。如果你对比特熊有话说,也能够留下你的声音。积极参与的小伙伴有机会取得比特熊精心筛选的礼物。 请大家积极参与的同时,退出“比特熊粉丝后援会”微信群,关注最新的流动信息和中奖名单。 P.S. –中奖信息将在本场直播后7个工作日内在“比特熊粉丝后援会”微信群中颁布。请留神接管高兴信息! 欢送大家继续关注【比特熊直播间】比特熊与你一起进阶,播种技能和高兴比特熊直播间,只做真直播 速速点击预约:B站 、CSDN 、流动行

June 13, 2022 · 1 min · jiezi

关于c++:6-月-TIOBE-榜单C-即将超越-Java-进入-Top3PHP-热度再下滑

近日,TIOBE 出炉了 2022 年 6 月份的编程语言趋势榜单。本次数据显示,C++ 的热度和风行趋势行将超过 Java,而 PHP 热度再下滑,已跌出前十。 近年来,Java 语言的受欢迎趋势仿佛逐步处于“被超过”的状态。2020 年 4 月份,Java 还排在 TIOBE 指数榜单的第一位,起初 Java 却不得不将第一名让给 C。再起初的 2021 年榜单里,Python 也凭借势不可挡的趋势超过了 Java。而当初看来,C++ 或将成为下一个超过 Java 的编程语言。 C++ 为何体现如此杰出?要害起因在于高性能的高级编程。C++ 语言每三年订正一次,而这些订正蕴含了开创性的新个性,使语言与 C# 、Java 并驾齐驱,且没有垃圾收集器的性能损失。 TIOBE 6 月榜单:Java、PHP 热度上涨排在榜单前 3 位的编程语言别离为: Python(评级为 12.20%,评分上涨+0.35%)、C(评级为11.91%,评分降落-0.64%)、Java(评级为 10.47%,评分降落-1.07%)。 近年来 Python 编程语言热度一路上涨,相比去年 6 月,此前榜单第 2 的 Python 现在曾经来到了第 1 名的地位,与此前排名第位的 C 地位产生了调换。而本月排在第 3 位的 Java 则“奄奄一息”,数据降落了 1.07%,简直要被排在第 4 位的 C++(评级为 9.63%,评分上涨+2.26%)超过。 排在榜单第 5-10 位的别离为:C#(评级为 6.12%,评分上涨+1.79%)、Visual Basic(评级为 5.42%,评分上涨+1.40%)、JavaScript(评级为2.09% ,评估降落-0.24%)、SQL(评分为1.94%,评分降落+0.06%)、Assembly language(评级为1.85%、评分降落-0.21%)、Swift(评级为1.55%,评分上涨+0.44%)。 ...

June 11, 2022 · 1 min · jiezi

关于c++:OSG365-VS2017编译记录

OSG3.6.5 + VS2017编译记录网上有很多对于OSG的编译教程,也有他人编好的库(链接在这里)。然而看了很多,不如本人编译一次,上面记录下本人的编译过程。 一、源码下载官网下载地址,顺次下载源码、第三方库、数据。 1.osg 3.6.5源码,解压至OpenSceneGraph文件夹。 2.第三方库 下载对应VS版本的库,也能够本人用VS编译(太麻烦了),笔者间接应用曾经编译好的第三方库。下载后解压至3rdParty文件夹。 3.数据,下载后解压至data文件夹。 二、编译工具VS2017 + CMake3.19.8 三、编译流程cmake配置1.关上osg源码目录,新建build和install文件夹。关上cmake,别离抉择源码文件夹和bulid文件夹。 2.配置第三方库门路为3rdParty文件夹,编译后装置文件夹install,设置编译的是debug还是release版本 3.配置第三方库的门路,即osg依赖的各种lib的门路,具体的配置能够参考如下,本人能够依据名称在3rdparty的lib文件夹中寻找对应的lib,没找的能够临时不论。 4.点击左下角Configure按钮,抉择对应VS2017编译器,x64版本,点击确定。若无谬误,则会提醒configure done;若有谬误,则依据谬误提醒批改对应的配置即可。(碰到本人无奈解决的,能够分割我,尽全力帮忙解答^^) 5.点击Generate,即会生成VS2017的工程,生成实现后,点击Open Project按钮,也能够间接去build文件夹中关上。 6.关上工程后,先抉择debug-x64;再右键单击ALL_BUILD工程生成,若camke配置没问题的话,通过漫长的期待,提醒全副胜利;最初,右键单击Install工程生成,就会将生成的库拷贝到cmake设置的install门路下。 7.改成release-x64,反复步骤6即可。 最初,心愿大家都能编译胜利,若有问题,欢送交换!

June 7, 2022 · 1 min · jiezi

关于c++:简明的c笔记

1. 公有成员:private公有成员变量或函数在类的内部是不可拜访的,甚至是不可查看的。只有类和友元函数能够拜访公有成员。在类外面不写是什么类型,默认是 private 的。 就是说如果要拜访公有成员,必须是成员函数才能够拜访,内部不能间接赋值 2. 爱护成员:protected派生类的定义如下:派生类的成员函数能够被父类给复用 类外不能拜访protected成员3. 构造函数 4. 析构函数析构函数有助于在跳出程序(比方敞开文件、开释内存等)前开释资源5. 拷贝构造函数拷贝构造函数通常用于:* 通过应用另一个同类型的对象来初始化新创建的对象。* 复制对象把它作为参数传递给函数。* 复制对象,并从函数返回这个对象。参考链接 6. 友元函数它有权拜访类的所有公有(private)成员和爱护(protected)成员参考链接7.内联函数类定义中的定义的函数都是内联函数,即便没有应用 inline 说明符(如何应用,在变量类型后面加一个关键字inline就行)如果一个函数是内联的,那么在编译时,编译器会把该函数的代码正本搁置在每个调用该函数的中央。8. this指针每一个对象都能通过 this 指针来拜访本人的地址,友元没有this指针9. 指向类的指针 10.动态成员当咱们申明类的成员为动态时,这意味着无论创立多少个类的对象,动态成员都只有一个正本。动态成员在类的所有对象中是共享的参考链接11. 继承(基类和派生类) 一个派生类继承了所有的基类办法,但下列状况除外:* 基类的构造函数、析构函数和拷贝构造函数。* 基类的重载运算符。* 基类的友元函数。参考链接 12. 重载运算符和重载函数重载函数:函数同名但类型不同名// 留神重载和重写的区别运算符重载:例如间接实现同一个类的不同成员的相加,间接用运算符重载实现参考链接 13. 多态就是派生类继承他的父类可能会重写父类的办法如果多个派生类都重写了父类的办法,在同一时间内,多个派生都同时应用该办法,可能会呈现抵触,就要在父类中会被重写的办法减少关键字virtual14. 纯虚函数在基类中定义虚函数,以便在派生类中从新定义该函数更好地实用于对象,然而您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。参考链接15. 文件和文件流参考链接 16. 异样解决try throw catch参考链接17. 动态内存C++程序中的内存分为两个局部:栈:在函数外部申明的所有变量都将占用栈内存。堆:这是程序中未应用的内存,在程序运行时可用于动静分配内存参考链接 18.命名空间参考链接 19. 模板(泛型的根底)参考链接 20. 预处理器预处理器是一些指令,批示编译器在理论编译之前所需实现的预处理。#include <库函数名>#define __ __预约义宏参考链接 21. sleep函数 22. 援用和指针援用变量是一个别名 参考链接23. 枚举enum 24. typedeftypedef int int1;//给int1类型实质就是int类型#define int //1、定义一个构造体 typedef struct A { int a ; int b ; }A1;25. #define#define 与typedef 的区别sizeof();size()length()字符串和字符数组字符串是一个类,要应用要申明头文件#include <string.h>string a="1234";字符数组char arr[6];//这是一个字符数组,每一个数组元素存取一个char ...

June 3, 2022 · 1 min · jiezi

关于c++:拯救工程师远程开发C的四大秘笈|视频教程

因为新冠疫情的影响,越来越多的国内公司开始反对近程办公 (https://github.com/LinuxSuRen...),OneFlow也是如此,简直所有的实习生与超过三分之一的全职研发人员都是近程办公。 作为一名技术人员,尤其是一名C++工程师,近程办公须要操心的首要问题可能就是“如何搭好用的近程开发环境”,具体包含本地和服务器的操作系统不统一怎么办?用不惯服务器上的编辑器、IDE怎么办?每次新机器都要从新配环境很苦楚怎么办? 只有想办,这些都不是问题。 从实践经验登程,B站Up主“不想吃糖liao”制作了“近程开发C++系列”手把手教学视频。不要被它的名字吓到了:C++的确很深奥,但那是其余系列要解决的问题。 在“近程开发C++系列”里,次要是介绍近程办公的必备工具、技能。置信有不少人对通过SSH登录服务器、Linux/Windows下对立的C++工程构建等操作并不相熟,从现在起,这些问题再也不必放心,Up主“不想吃糖liao”将向你分享近程开发的上手秘笈,请留神查收! 秘笈一:VS Code插件 Remote SSH https://www.bilibili.com/vide... 小糖展现了如何通过SSH登录一个服务器,同时介绍一款十分好用的VS Code插件Remote SSH,该插件能够让咱们在近程服务器开发像在本地开发一样简略。 秘笈二:不会在Linux/Windows下装置软件?Conda帮你一键搞定 https://www.bilibili.com/vide... 很多人都有这样的经验:想要疾速上手一个我的项目的时候,却发现搭环境都要耗个十天半个月,不是动静库找不到,就是头文件找不到,再者,跑起来又发现依赖的包的版本又不对。因而,小糖向大家举荐了一款环境治理神器Conda,同时介绍了Conda的根本应用和用Conda启动《入手深度学习》的学习环境。 秘笈三:编译C++我的项目必备CMake https://www.bilibili.com/vide... 秘笈四:Linux下如何打造C++完满开发IDE:clangd https://www.bilibili.com/vide... 个别咱们在Windows上做C++开发首选的IDE是Visual Studio,Visual Studio号称宇宙第一IDE,也的确十分好用,但如果须要在Linux上做C++开发,那该怎么办?托LLVM和VSCode的福,只有领有VSCode,再配上clangd插件,就能够使VSCode领有和IDE一样的体验。小糖在本期内容中为具体介绍了clangd插件的性能及其下载和应用办法。 以上就是C++近程开发的次要内容。欢送关注小糖的B站账号“不想吃糖liao”,更多C++相干内容等你来发现。 欢送下载体验 OneFlow v0.7.0 最新版本:https://github.com/Oneflow-In...

May 31, 2022 · 1 min · jiezi

关于c++:浅谈c中的Pimpl

浅谈c++中的Pimpl什么是Pimpl?Pimpl 意思为“具体实现的指针”(Pointer to Implementation), 它通过一个公有的成员指针,将类的实现细节进行暗藏,从而达到缩小依赖、暗藏实现的目标。 利用实例1、如果有如下场景: Project A援用了多个第三方库OSG来实现具体的性能。Project B援用了 A,这时候如果A减少了osg的依赖,B在应用A时就很难防止不应用到OSG,这样对于B又须要从新编译等等,十分麻烦。2、解决办法: 利用类的前置申明 + 公有成员指针3、具体实现: ClassA.h 头文件 #pragma once class ClassAPrivate; //公有类前置申明 class ClassA { public: ClassA(); ~ClassA(); //测试 void testFun(); private: //公有指针 ClassAPrivate* d_ptr; };ClassA.cpp 源文件 #include "ClassA.h" #include "ClassAPrivate.h" ClassA::ClassA() :d_ptr(new ClassAPrivate(this)) { } ClassA::~ClassA() { } void ClassA::testFun() { d_ptr->testFun(); //函数用公有类实现 }ClassAPrivate.h 公有类头文件 #pragma once #include "osg/Node" class ClassA; //私有类前置申明 class ClassAPrivate : public osg::Node { public: ClassAPrivate(ClassA *qPtr); ~ClassAPrivate(); void testFun(); ClassA* q_ptr; //保留共有类指针,可能须要调用私有类函数 };公有类源文件依据具体需要实现即可。 ...

May 30, 2022 · 1 min · jiezi

关于c++:DeepRoute-Lab-C大杀器超实用在线工具推荐

C++作为语法最简单、写代码时最须要思前顾后的语言,咱们不在身边顺手备用几个“大杀器”在线工具,可能真的不是很利于工作的发展呐。 置信大家对上面这两个网页曾经十分相熟了,它们是编写代码过程中必不可少的工具宝典。 1. cppreference2. cplusplus** 上述两个网页次要是提供十分详尽的语法层面的材料。 除此之外,我将从其余各个方面给大家举荐几个绝对小众然而十分实用的在线工具。 置信我,接触了这几个工具后,你肯定会爱上它们的。 实用在线工具 ✦首先,这几个工具具备如下的通用性能 01 设置运行平台、编译器及版本 x86、x64、arm gcc、clang 7.5.0、9.4.0,etc 02 设置C++语言版本 c++11、c++14,etc 03 设置编译优化选项 Og、O1、O2,etc 上面,我将联合本人的应用教训,顺次介绍这几个工具的典型利用场景和应用成果。 从编译器的角度看源码这就是C++ Insight 咱们在写代码的时候,如果不是对C++规范和编译器一目了然,可能很难晓得编译器在底下到底做了什么。应用C++ Insights,能够帮咱们一探到底。 应用花括号初始化,编译器保障了所有的成员函数都会被(递归地)初始化。 帮忙咱们一览C++ 14的generic lambda expression 是怎么被编译器开展的。 展现了编译器在用户不自定义构造函数时,会主动生成对应的构造函数(到这里一切正常)。 这里仅仅是在原有代码中新增了一个默认析构函数,如果没有看到编译器生成的代码,可能很难设想挪动构造函数基本不会生成吧?起因是什么呢?能够自行搜寻一下 rule of five 和 rule of zero。 具体到这个例子,因为如果你的类外面只申明了自定义的/默认的 copy (ctor & assignment operator) 或者 destructor,那么他们会 suppress 编译器生成默认的 move (ctor & assignment operator) 。 联合C++ Insights,咱们能够很不便地领会模板参数匹配和援用折叠。 实时汇编剖析这就是赫赫有名的Compiler Explorer 它次要用来做实时汇编的生成,帮忙咱们疾速剖析代码片段在不同设置下的汇编代码生成,疾速提供代码优化方向,并阻止咱们自作聪明地去优化代码,感触编译器的弱小。 下面两张图通知咱们不要在古代编译器背后班门弄斧…… clang 真是威力无穷啊,间接返回了编译器的后果。 ...

May 30, 2022 · 1 min · jiezi

关于c++:翻译Traits一种新的而且有用的Template技巧

文章来自Traits: a new and useful template technique 应该是很老(1995)的文章了,不过很适宜作为Template入门的资料。 ANSI/ISO C++规范库一开始就想反对国际化(internationalization),尽管一开始还没相好具体细节,然而最近5年逐步有点头绪了。当初失去的论断是,该当用template来对须要进行字符操作的工具进行参数化。 给现有的iostream和string类型进行参数化其实挺难的,须要创造一种新的技术才行。侥幸的是,这种技术能够很好的服用在其余中央。 问题在iostream中,streambuf须要一个EOF来实现本身的性能。在个别的库中,EOF就是一个int而已;一些须要读取字符的函数也只返回int数值。 class streambuf { ... int sgetc(); // return the next character, or EOF. int sgetn(char*, int N); // get N characters. };但如果用一种字符类型来参数化streambuf,会产生什么?一般来说,程序并不需要这个类型,而是须要这个类型的EOF的值。先试试看: template <class charT, class intT> class basic_streambuf { ... intT sgetc(); int sgetn(charT*, int N); };这个多进去的intT就有点烦人了。库的应用刚才不关怀所谓的EOF是啥。问题还不只这个,sgetc在遇到EOF时应该返回什么?莫非要再来一个模板参数?看来这种形式行不通。 Traits技法这时候就须要引入Traits了。有了traits,就不须要从原来的模板里间接取参数,而是定义一个新的模板。用户个别不会间接应用这个新的模板,所以这个模板名字能够起的人性化一点。 template <class charT> struct ios_char_traits { };默认的traits是个空类。对于实在的字符类型,能够特化这个模板以提供有意义的语义。 struct ios_char_traits<char> { typedef char char_type; typedef int int_type; static inline int_type eof() { return EOF; } };ios_char_traits<char>并没有数据成员,只有一些定义。再看看streambuf该怎么定义。 ...

May 27, 2022 · 2 min · jiezi

关于c++:翻译c类中空成员的优化

文章来自于The "Empty Member" C++ Optimization。是我在看c++ std::string代码时遇到的一个链接,其中解释了为什么_Alloc_hider会采纳inhert from Alloc的起因。文章应该是97年的,所以外面的指针长度还是4 byte。c++类中“空成员”的优化C++规范库中有很多有用的模板,包含享誉盛名的SGI STL。这些模板的实现很高效,也不失灵便。在日常的编程中,能够把这些模板当作范例来进行学习,也可启发咱们如何进行兼顾灵活性与效率的程序设计。 “空成员”的优化,就是这样的一个榜样:一个没有类成员的class,就不应该占用内存空间。什么状况下须要一个没有类成员的class呢?这样的class个别会领有一系列的typedef或者成员函数,而程序的调用方能够用本人定义的相似的class来实现一些非凡的性能(自定义的class可不肯定没有类成员)。这个默认提供的class应该能够满足绝大多数的需要。这种状况下,优化这个空成员的class是个很有性价比的事件。 因为语言的限度(之后会解释),空成员的class通常会占据肯定的内存空间。如果是个别状况也就算了,然而在stl里,不进行优化的话,还是会劝退很多潜在的使用者的。 空成员“收缩”以STL举例。每个STL的容器都有一个allocator的参数,当容器须要内存的时候,它会向allocator去申请。如果用户想要本人定制化内存申请过程,那么就能够在结构容器时提供本人的allocator。大多数状况下,容器用的是STL默认的allocator,这个默认的allocator间接调用new来实现调配。这是个空类,相似于上面这个定义 template <class T> class allocator { // an empty class . . . static T* allocate(size_t n) { return (T*) ::operator new(n * sizeof T); } . . . };举个list的例子,class list保留了一个公有的allocator成员,这个成员在构造函数里进行赋值 template <class T, class Alloc = allocator<T> > class list { . . . Alloc alloc_; struct Node { . . . }; Node* head_; public: explicit list(Alloc const& a = Alloc()) : alloc_(a) { . . . } . . . };成员list<>::alloc_通常占据4 byte,只管这个Alloc是个空类。这通常来说不太会是个问题。但万一list本身是一个微小的数据结构的一个节点(比方vector<list>),当vector很大的时候,这种额定的空间耗费是不可漠视的。微小的内存占用意味着更慢的执行速度。就算在当下,绝对于cpu本身的频率来说,内存拜访曾经十分慢了。 ...

May 26, 2022 · 2 min · jiezi

关于c++:Effective-c条款2尽量以constenuminline替换define

条款2(Clause 2):Prefer consts, enums, inlines to #defines 1应用const替换#define比方:将上面的替换 #define ASPECT_R 1.00为 const double AspectR=1.00;起因:可能记号名称ASPECT_R未进入记号表内,当你使用这个常量的时候,显示的报错信息外面可能不会提到ASPECT_R,只提到了1.00,所以找不到谬误在哪里。而应用const就不会呈现这种状况。 两种非凡状况1,定义常量指针(constant pointer)写两次constconst char* const name="Yap Miracle";//上面这样更好const std::string name("Yap Miracle");2,class专用常量不必宏定义来实现函数别用这种函数 #define CALL_WITH_MAX(a, b) F((a) > (b) ? (a): (b))应用 template <typename T>inline void callWithMax(const T& a,const T& b){ f(a > b ? a : b); //f为简略比拟函数}这种写法有很多益处,它恪守作用域和拜访规定。 最初请记住1、对于单纯常量,最好以const对象替换#define。2、对于形似函数的宏,最好改用inline替换#define。3、#include和#ifdef,#ifndef依然是必需品。

May 16, 2022 · 1 min · jiezi

关于c++:ECECS-472572-C求解

Final ProjectECE/CS 472/572 Final Exam ProjectLate submissions will be penalized 15 points per day.Remember to check the errata section (at the very bottom of the page) for updates.Your submission should be comprised of two items: a .pdf file containing your written report and a.tar file containing a directory structure with your C or C++ source code. Your grade will be reduced ifyou do not follow the submission instructions.All written reports (for both 472 and 572 students) must be composed in MS Word, LaTeX, or some otherword processor and submitted as a PDF file.Please take the time to read this entire document. If you have questions there is a high likelihood thatanother section of the document provides answers.IntroductionIn this final project you will implement a cache simulator. Your simulator will be configurable and will beable to handle caches with varying capacities, block sizes, levels of associativity, replacement policies,and write policies. The simulator will operate on trace files that indicate memory access properties. Allinput files to your simulator will follow a specific structure so that you can parse the contents and use theinformation to set the properties of your simulator.After execution is finished, your simulator will generate an output file containing information on thenumber of cache misses, hits, and miss evictions (i.e. the number of block replacements). In addition,the file will also record the total number of (simulated) clock cycles used during the situation. Lastly, thefile will indicate how many read and write operations were requested by the CPU.It is important to note that your simulator is required to make several significant assumptions for the sakeof simplicity. ...

May 15, 2022 · 22 min · jiezi

关于c++:一文详解C中运算符的使用

目录一、算术运算符二、关系运算符三、逻辑运算符四、位运算符五、赋值运算符六、杂项运算符 一、算术运算符运算符 形容 把两个操作数相加从第一个操作数中减去第二个操作数把两个操作数相乘/ 分子除以分母% 取模运算符,整除后的余数++ 自增运算符,整数值减少 1– 自减运算符,整数值缩小 1通过上面的例子能够让咱们更好的了解C++中的运算符的意义与应用办法。#include <iostream>using namespace std; int main(){ int a = 66; int b = 33; int c; c = a + b; cout << "a + b 的值是 " << c << endl ; c = a - b; cout << "a - b 的值是 " << c << endl ; c = a * b; cout << "a * b 的值是 " << c << endl ; c = a / b; cout << "a / b 的值是 " << c << endl ; c = a % b; cout << "a % b 的值是 " << c << endl ; return 0;}输入: ...

May 14, 2022 · 3 min · jiezi

关于c++:Electron-插件开发实践

前言晚期跨平台桌面利用开发大多采纳 Qt 和 C++,受语言学习老本开发效率影响,越来越多的人将眼光转向了 Electron。Electron 是以 Nodejs 和 Chromium 为内核的跨平台开发框架。 Electron 基于 Web 技术开发桌面利用,Web 技术在软件开发畛域利用十分宽泛,生态较为成熟,学习老本较低、开发效率高。然而 Web 在解决多线程、并发场景时显得顾此失彼,Electron 底层有 Nodejs 反对,Nodejs 的插件模块具备调用 C++ 的能力,C++ 非常适合解决高并发、音视频等简单业务,补救了 Web 的性能问题。本文就 js 和 C++ 混合编程在 Electron 桌面程序中的利用进行介绍。 Nodejs 中应用 C++,有以下几种形式: 将 C++ 程序作为独立子过程应用。通过 node-ffi 形式调用。Nodejs 扩大,将 C++ 代码编译为 Nodejs 模块,本文次要针对这种形式进行介绍。C++ 扩大C++ 扩大简介Nodejs 自身采纳 C++ 编写,所以咱们能够应用 C++ 编写的本人的 Nodejs 模块,能够像 Nodejs 原生模块一样应用。C++ 扩大格局为 .node,其本质为动态链接库,相当于 Windows 下 .dll。C++ 扩大作为动态链接库,通过 dlopen 在 Nodejs 中加载。 C++ 扩大架构图: ...

May 12, 2022 · 3 min · jiezi

关于c++:记录平时遇到的一些注意点

WM_COPYDATA留神点typedef struct tagCOPYDATASTRUCT { ULONG_PTR dwData; DWORD cbData; PVOID lpData;} COPYDATASTRUCT, *PCOPYDATASTRUCT;/********正文:1、dwData.为自定义数据;2、cbData.即lpData指向的数据的长度,要是这个变量的值设置谬误,就会导致WM_COPYDATA传输/*数据失败;3、lpData.传输的数据.最好应用根底数据类型;********/应用WM_COPYDATA时要用SendMessage而不能应用PostMessage,因为SendMessage是阻塞的,会期待音讯响应窗体解决音讯结束后再返回;而PostMessage是异步的,这样就可能会导致当音讯响应窗体接管到WM_COPYDATA的时候,COPYDATASTRUCT对象曾经被析构了,导致拜访数据产生异样; 因为应用SendMessage,所以不应该在WM_COPYDATA中解决数据,能够在音讯响应窗体的WM_COPYDATA中先把COPYDATASTRUCT对象中的数据复制进去,通过自定义音讯发送到音讯响应窗体,而后立刻返回,来缩小父过程的阻塞工夫。这样就把解决数据的代 case WM_COPYDATA: { COPYDATASTRUCT* data = (COPYDATASTRUCT*)lParam; // TODO: 解决pCopyData->lpData指向的数据 } break;

May 12, 2022 · 1 min · jiezi

关于c++:c-volatile的一些理解

含意在这里,咱们将理解 C++ 中 volatile 限定符的含意。volatile 限定符在咱们申明变量时利用到它。它用于通知编译器,该值可能随时更改。这些是 volatile 的一些属性。 volatile 关键字不能删除内存调配。 它不能缓存寄存器中的变量。该值不能按调配程序更改。让咱们看看如何应用 volatile 关键字。volatile int a;int volatile a;这里这两个申明是正确的。像其余数据类型一样,咱们能够应用 volatile 指针、构造体、联合体等。 volatile 构造体和联合体自身能够是 volatile,它们的成员变量也能够是 volatile 类型。 volatile 用在不同的中央。对于内存映射的外设寄存器,一些全局变量,由一些其余函数或中断服务程序拜访,或者在一些多线程应用程序中,能够应用 volatile。例子 int main (){ int value; value++;}int main (){ volatile int value; value++;}有两个代码块。在第一个块中,不存在 volatile 关键字。因而对于第一种状况,变量将从内存复制到 CPU 寄存器,而后执行操作。在第二种状况下,存在volatile,所以在这种状况下,变量不会从内存复制到寄存器。 思考上面的代码int some_int = 100;while(some_int == 100){ //your code}当这个程序被编译时,编译器可能会优化这个代码,如果它发现程序素来没有尝试扭转some_int的值,所以它可能会试图通过将循环从更改为等价的货色来优化while循环执行可能很快(因为循环中的条件仿佛总是一样的)。(如果编译器不对其进行优化,那么它必须在每次迭代中获取 100 的值并将其与 100 进行比拟,这显然有点慢。)while(some_int == 100) while(true) while true some_int 然而,有时,(程序的某些局部的)优化可能是不可取的,因为可能是其他人正在some_int从程序内部更改编译器不晓得的值,因为它看不到它;但这就是你设计它的形式。在这种状况下,编译器的优化不会产生预期的后果! 因而,为了确保取得所需的后果,您须要以某种形式阻止编译器优化while循环。这就是volatile关键字发挥作用的中央。你须要做的就是这个, volatile int some_int = 100; //note the 'volatile' qualifier now!换句话说,我将解释如下: ...

May 11, 2022 · 1 min · jiezi

关于c++:对于单例模式双重检查的一些理解

一、首先从形而上角度看,我认为很多文章都在把两个指标(我称为单例指标和平安指标)混在一起谈。留神这是两个指标,1是是否单例;2是在多线程下是否牢靠。双重锁只是保障了指标1,与指标2无关。其实你想一下,1个if解决不了指标2,2个if就行了?那3个if岂不成果更好? 二、具体来看。有人说1if为效率(防止都申请锁)【我认为不精确】;2if为防止反复new。(1)首先,双重查看锁不肯定非用到单例问题上。用到别处(2中也未必是做new工作),可能1,2都为效率。(2)就单例问题而言,1if原本就是单例模式要求的,谈不上什么效率,2if才是减少的,能防止反复new,从而在多线程环境下没毁坏“指标1”。(3)至于指标2,问题出在p==null为假时。p不空,不代表你马上应用就没问题(因为编译重排、硬件等各种起因,对象还没有初始化好就被你看到了) 。这一点对1if,2if都实用,所以你就是加3个if,或者加volatile,也还是未必能保障你看到的、不空的p能用(前提是p是刚new的,只有是new的问题,那影响因素太多了:单例外部还有其余数据成员是否筹备好、编译优化、OS、多CPU调度、CPU外部。。。)(4)所以我感觉双重锁,只有是用在单例问题上,从根本上看是有平安问题的,只是在你某个具体平台上好使而已。![3Y(LCJ2]T`SQN76BC29K8}U.png](/img/bVcZFTm)

May 11, 2022 · 1 min · jiezi

关于c++:祖师级技术人的哲理认知热爱恒心

在“技术名人堂”专辑中,C++之父Bjarne Stroustrup首先带来了他和C++的往事。在他看来,本人长期对历史、哲学抱持的宽泛趣味,对推动这一语言的倒退具备重要意义。 C#和TypeScript之父Anders Hejlsberg也带来他对开发者的坦诚倡议。对于他来说,没有什么比“酷爱”更能诠释取得极大胜利的起因。“只有当创立出一门编程语言并实现编译器和工具,你能力成为本人世界的客人。”  在MySQL之父Michael “Monty” Widenius看来,“一个十分杰出的程序员能够抵五个个别的程序员。对于所有中国开发者,我只想说,请保持你的工作,你曾经做得十分好了,肯定不要进行写代码。” 细品祖师级技术专家给到开发者的倡议,他们想要表白的别离在于:思考力、精神力,以及持久力。 1.要关上认知,不能只把本人当成“码农”,而应以迷信思维自立,融汇事实世界中各类问题的思考; 2.灵感和能源的根源是“酷爱,要为“代码”赋予爱的灵魂,能力成为它的客人; 3.相较于极少数的少年成才,绝大部分人终会大器晚成,只有不忘初心,坚持不懈。

May 10, 2022 · 1 min · jiezi

关于c++:CC气象数据中心实战手把手教你做工业级项目源码齐全

C/C++气象数据中心实战,手把手教你做工业级我的项目(源码齐全)超清原画 残缺无密 资料齐全 获取ZY:百度网盘一个Java注解@Recover搞定俊俏的循环重试代码 使用背景在实际我的项目中其中一部分逻辑可能会因为调用了内部服务或者等待锁等情况下出现不可预料的异样,在这个时候咱们可能需要对调用这部分逻辑进行重试,代码外面次要就是使用for循环写一大坨重试的逻辑,各种硬编码,各种辣眼睛的补丁。 特地是针对重试的逻辑,到处都有。所以我决定用一个重试组件spring-retry优化一波。它的出现,解决掉这部分俊俏的代码! 2开始上代码首先引入依赖: org.springframework.retryspring-retry1.3.2复制代码因为该组件是依赖于 AOP 给你的,所以还需要引入这个依赖(如果你其余 jar 包中引用过了,当然也就不需要再次引用了): org.springframework.bootspring-boot-starter-aop2.6.1复制代码开启重试:@SpringBootApplication@EnableRetrypublic class ApplicationStarter { public static void main(String[] args) { SpringApplication.run(ApplicationStarter.class); }}复制代码Controller层@RestControllerpublic class TestController {@Autowiredprivate IRecursiveCallService recursiveCallService; @GetMapping("test2")public Object test2() { return recursiveCallService.testService();}}复制代码Service层public interface IRecursiveCallService { /** * 测试service * * @return */List testService();}复制代码Service层具体实现@Servicepublic class RecursiveCallServiceImpl implements IRecursiveCallService { @Override@Retryable(recover = "testService3")public List testService() { System.out.println("到此一游!"); System.out.println(1 / 0); return null;}@Recoverpublic List testService1() { System.out.println("谬误的返回"); return Collections.singletonList("S");}@Recoverpublic List testService2(String i) { System.out.println("正确的返回"); return Collections.singletonList(1);}@Recoverpublic List testService3() { System.out.println("正确的返回2"); return Collections.singletonList(2);}} ...

May 10, 2022 · 1 min · jiezi

关于c++:c-stdthread-joindetach用法

detach拆散线程,将对象示意的线程与调用线程拆散,容许它们彼此独立执行。两个线程在没有阻塞或同步的状况下持续运行。留神,当任何一个完结执行时,它的资源都会被开释。让被创立的线程为后盾线程,否则主线程退出时,如果子线程没有退出则异样。 #include <iostream>#include <thread>using namespace std;void func1() { cout << "func1" << endl;}void func2() { cout << "func2" << endl;}int main() { thread t1(func1); thread t2(func2); return 0;}如果间接执行下面的程序,会报错: void func1() {    std::cout << "func1" << std::endl;}void func2() {    std::cout << "func2" << std::endl;}拆散后,则失常: std::thread t1(func1);t1.detach();std::thread t2(func2);t2.detach();join在下面的状况中,个别应用join来解决: #include <iostream>#include <thread>using namespace std;void func1() { cout << "func1" << endl;}void func2() { cout << "func2" << endl;}int main() { thread t1(func1); t1.join(); thread t2(func2); t2.join(); return 0;}然而还是有可能还是会呈现问题,异常情况下可能会存在资源泄露的问题,利用c++的rall机制,能够在析构函数中join,自定义线程类: ...

May 6, 2022 · 1 min · jiezi

关于c++:Blackjack-游戏开发

BlackjackIntro:Blackjack is a comparing card game between one or more players and a dealer, where each player in turncompetes against the dealer. Players do not compete against each other. It is played with one or more decksof 52 cards, and is the most widely played casino banking game in the world.[1] <Blackjack>Now, in this project, you are required to implement 1 Human vs 1 Computer blackjack.Game Description:In the game, the winner with the highest the number of points must have 21 points or less. Blackjack meansget Ace and ten-value at same time in the licensing phase. Each player wants to win the game as much aspossible, and the criteria are as follows:If the player is dealt an blackjack, and the dealer does not, the player wins, vice versa.If the player exceeds a sum of 21 ("busts"), the player loses, vice versa.If the player attains a final sum higher than the dealer and does not bust, the player wins, vice versa.If both dealer and player receive a blackjack or any other hands with the same sum called a "push", noone wins.Main rules and flow path:rules:There are 52 cards in each deck, except two jokers.Two decks of playing cards are used at a game. The deck will continue to be played in each subsequentround until the number of cards left is less than half or renewing the game. At this point, the cards arereshuffled.The value of cards two through ten is their pip value. Jack, Queen, and King are all worth ten. Aces can beworth one or eleven.In the game, the computer is the dealer, and the person is the player.No one can have more than five cards in his hand.The order of the draw is the sequential draw.All cards drawn in Hit are exposed.flow path: ...

May 5, 2022 · 6 min · jiezi

关于c++:C单例模式双重锁漏洞内存读写的乱序执行编译器问题

阐明首先解释为什么会呈现这个问题:在懒汉模式下存在多线程不平安的问题(饿汉模式是线程平安的),为了解决这个问题,首先采纳的是利用C++中lock_guard类,这个类实现原理采纳RAII,不必手动治理unlock。 class singleton {private: singleton() {} static singleton *p; static mutex lock_;public: static singleton *instance();};singleton *singleton::p = nullptr;singleton* singleton::instance() { lock_guard<mutex> guard(lock_); if (p == nullptr) p = new singleton(); return p;}解决了懒汉模式的这个问题,又呈现了性能问题:每次执行都会有加锁开释锁, 而这个步骤只有在第一次new Singleton()才是有必要的. 因而引出DCL 双重查看锁模式class singleton {private: singleton() {} static singleton *p; static mutex lock_;public: singleton *instance(); // 实现一个内嵌垃圾回收类 class CGarbo { public: ~CGarbo() { if(singleton::p) delete singleton::p; } }; // 2022-4-21 // 所谓的垃圾回收,就是定义一个动态的类,类外面只有一个办法,这个办法查看singleton::p是否是空,不是空,执行delete // 因为是动态的办法,程序会主动的开释该对象,从而达到主动回收的机制。 static CGarbo Garbo; // 定义一个动态成员变量,程序完结时,零碎会主动调用它的析构函数从而开释单例对象};singleton *singleton::p = nullptr;singleton::CGarbo Garbo;singleton* singleton::instance() { if (p == nullptr) { lock_guard<mutex> guard(lock_); if (p == nullptr) p = new singleton(); } return p;}留神咱们的题目是单例模式双重锁破绽。 ...

May 3, 2022 · 1 min · jiezi

关于c++:浅谈重写操作符CSE111

CSE-111 • Spring 2021 • Program 1 • Overloading and operators Using C++11/14/17 (20?)All programming in this course will be done C++ style, not C style, as shown in thefollowing table.Do not use : Instead, use :char* strings <string>C arrays <vector><stdio.h>, <cstdio> <iostream>, <iomanip>pointers <shared_ptr>union inheritance<header.h> <cheader>Include only C++11/14/17 header files where feasible : using namespace std;Include <cheader> files only when C++-style files are unavailable. Include <header.h> files from C only when an appropriate <cheader> files is unavailable. Use thescript cpplint.py.perl (a wrapper for cpplint.py) to check style.OverviewThis assignment will involve overloading basic integer operators to perform arbitraryprecision integer arithmetic in the style of dc(1). Your class bigint will intermixarbitrarily with simple integer arithmetic.To begin read the man(1) page for the command dc(1) :man -s 1 dcA copy of that page is also in this directory. Your program will use the standard dcas a reference implemention and must produce exactly the same output for thecommands you have to implement :+-*/%^cdfpqIf you have any questions as to the exact format of your output, just run dc(1) andmake sure that, for the operators specified above, your program produces exactlythe same output. A useful program to compare output from your program with thatof dc(1) is diff(1), which compares the contents of two files and prints only the differences.Also look in the subdirectory misc/ for some examples.See also :• dc (computer program)https://en.wikipedia.org/wiki...(computer_program)• dc, an arbitrary precision calculatorhttps://www.gnu.org/software/...Implementation strategyAs before, you have been given starter code.(a) Makefile, debug, and util If you find you need a function which does not properlybelong to a given module, you may add it to util.CSE-111 • Spring 2021 • Program 1 • Overloading and operators 2 of 5(b) The module scanner reads in tokens, namely a NUMBER, an OPERATOR, or SCANEOF.Each token returns a token_t, which indicates what kind of token it is (theterminal_symbol symbol), and the string lexinfo associated with the token.Only in the case of a number is there more than one character. Note that oninput, an underscore (_) indicates a negative number. The minus sign (-) isreserved only as a binary operator. The scanner also has defined a couple ofoperator<< for printing out scanner results in debug mode.(c) The main program main.cpp, has been implemented for you. For the six binaryarithmetic functions, the right operand is popped from the stack, then the leftoperand, then the result is pushed onto the stack.(d) The module iterstack can not just be the STL stack, since we want to iteratefrom top to bottom, and the STL stack does not have an iterator. A stackdepends on the operations back(), push_back(), and pop_back() in the underlyingcontainer. We could use a vector, a deque, or just a list, as long as the requisiteoperations are available.Class bigintThen we come to the most complex part of the assignment, namely the class bigint.Operators in this class are heavily overloaded.(a) Most of the functions take a arguments of type const bigint&, i.e., a constantreference, for the sake of efficiency. But they have to return the result byvalue.(b) The operator<< can’t be a member since its left operand is an ostream, so wemake it a friend, so that it can see the innards of a bigint. Note now dc printsreally big numbers.(c) The relational operators == and < are coded individually as member functions.The others, !=, <=, >, and >= are defined in terms of the essential two.(d) All of the functions of bigint only work with the sign, using ubigint to do theactual computations. So bigint::operator+ and bigint::operator- will checkthe signs of the two operands then call ubigint::operator+ or ubigint::operator-,as appropriate, depending on the relative signs and magnitudes. Themultiplication and division operators just call the corresponding ubigint operators,then adjust the resulting sign according to the rule of signs.Class ubigintClass ubigint implements unsigned large integers and is where the computationalwork takes place. Class bigint takes care of the sign. Now we turn to the representationof a ubigint, which will be represented by vector of bytes.(a) Replace the declarationusing unumber = unsigned long;unumber uvalue {};withusing ubigvalue_t = vector<uint8_t>;ubigvalue_t ubig_value;in the header file <ubigint.h>. The type uint8_t is an unsigned 8-bit integerCSE-111 • Spring 2021 • Program 1 • Overloading and operators 3 of 5defined in <cstdint>.(b) In storing the big integer, each digit is kept as an integer in the range 0 to 9 inan element of the vector. Since the arithmetic operators add and subtractwork from least significant digit to most significant digit, store the elements ofthe vector in the same order. That means, for example, that the number 4629would be stored in a vector v as : v3 = 4, v2 = 6, v1 = 2, v0 = 9. In other words,if a digit’s value is d × 10k, then vk = d.(c) In order for the comparisons to work correctly, always store numbers in acanonical form : After computing a value from any one of the six arithmeticoperators, always trim the vector by removing all high-order zeros :while (size() > 0 and back() == 0) pop_back();Zero should be represented as a vector of zero length and a positive sign.(d) The scanner will produce numbers as strings, so scan each string from the endof the string, using a const_reverse_iterator (or other means) from the end ofthe string (least significant digit) to the beginning of the string (most signifi-cant digit) using push_back to append them to the vector.Implementation of Operators(a) For bigint::operator+, check to see if the signs are the same or different. Ifthe same, call ubigint::operator+ to compute the sum, and set the result signas appopriate. If the signs are different, call ubigint::operator- with thelarger number first and the smaller number second. The sign is the sign of thelarger number.(b) The operator bigint::operator- should perform similarly. If the signs are different,it uses ubigint::operator+ but if the same, it uses ubigint::operator-.(c) To implement ubigint::operator+, create a new ubigint and proceed from thelow order end to the high order end, adding digits pairwise. For any sum >=10, take the remainder and add the carry to the next digit. Use push_back toappend the new digits to the ubigint. When you run out of digits in theshorter number, continue, matching the longer vector with zeros, until it isdone. Make sure the sign of 0 is positive.(d) To implement ubigint::operator-, also create a new empty vector, startingfrom the low order end and continuing until the high end. If the left digit issmaller than the right digit, the subtraction will be less than zero. In thatcase, add 10 to the digit, and set the borrow to the next digit to −1. After thealgorithm is done, pop_back all high order zeros from the vector before returningit. Make sure the sign of 0 is positive.(e) To implement operator==, check to see if the signs are the same and thelengths of the vectors are the same. If not, return false. Otherwise run downboth vectors and return false as soon a difference is found. Otherwise returntrue.(f) To implement operator<, remember that a negative number is less than a positivenumber. If the signs are the same, for positive numbers, the shorter one isless, and for negative nubmers, the longer one is less. If the signs and lengthsare the same, run down the parallel vectors from the high order end to the lowCSE-111 • Spring 2021 • Program 1 • Overloading and operators 4 of 5order end. When a difference is found, return true or false, as appropriate. Ifno difference is found, return false.(g) Implement function bigint::operator*, which uses the rule of signs to determinethe result. The number crunching is delegated to ubigint::operator*,which produces the unsigned result.(h) Multiplication in ubigint::operator* proceeds by allocating a new vectorwhose size is equal to the sum of the sizes of the other two operands. If u is avector of size m and v is a vector of size n, then in O(mn) speed, perform anouter loop over one argument and an inner loop over the other argument,adding the new partial products to the product p as you would by hand. Thealgorithm can be described mathematically as follows :p ← for i ∈ [0, m) :c ← 0for j ∈ [0, n) :d ← pi+ j + uivj + cpi+ j ← d rem 10c ← d ÷ 10pi+n ← cNote that the interval [a, b) refers to the set {x|a ≤ x < b}, i.e., to a half-openinterval including a but excluding b. In the same way,apair of iterators inC++ bound an interval.(i) Long division is complicated if done correctly. See a paper by P. BrinchHansen, ‘‘Multiple-length division revisited : A tour of the minefield’’, Software— Practice and Experience 24, (June 1994), 579–601. Algorithms 1 to 12 areon pages 13–23, Note that in Pascal, array bounds are part of the type, whichis not true for vectors in C++.multiple-length-division.pdfhttp://brinch-hansen.net/pape...http://citeseerx.ist.psu.edu/...(j) The function divide as implemented uses the ancient Egyptian division algorithm,which is slower than Hansen’s Pascal program, but is easier to understand.Replace the long values in it by vector<digit_t>. The logic is shownalso in misc/divisioncpp.cpp. The algorithm is rather slow, but the big-Oanalysis is reasonable.(k) Modify operator<<, first just to print out the number all in one line. You willneed this to debug your program. When you are finished, make it print numbersin the same way as dc(1) does.(l) The pow function uses other operations to raise a number to a power. If theexponent does not fit into a single long print an error message, otherwise dothe computation. The power function is not a member of either bigint or ubigint,and is just considered a library function that is implemented using moreprimitive operations.CSE-111 • Spring 2021 • Program 1 • Overloading and operators 5 of 5Memory leak and other problemsMake sure that you test your program completely so that it does not crash on a SegmentationFault or any other unexpected error. Since you are not using pointers,and all values are inline, there should be no memory leak. Use valgrind(1) to checkfor and eliminate uninitialized variables and memory leak.If your program is producing strange output or segmentation faults, use gdb(1) andthe debug macros in the debug module of the code/ subdirectory.Version of g++The code must compile and run using g++ on unix.ucsc.edu, regardless of whether itruns elsewhere. When this document was formatted that was :bash-$ which g++/opt/rh/devtoolset-8/root/usr/bin/g++bash-$ g++ --version | head -1g++ (GCC) 8.3.1 20190311 (Red Hat 8.3.1-3)bash-$ echo $(uname -sp) - $(hostname) - $(date)Linux x86_64 - unix6.lt.ucsc.edu - Fri Mar 26 00:01:02 PDT 2021What to submitSubmit source files and only source files : Makefile, README, and all of the headerand implementation files necessary to build the target executable. If gmake does notbuild ydc your program can not be tested and you lose 1/2 of the points for theassignment. Use checksource on your code to verify basic formatting.Look in the .score/ subdirectory for instructions to graders. Read Syllabus/pairprogramming/and also submit PARTNER if you are doing pair programming. Eitherwa y submit the README described therein.Et cetera ( ‘´).The accuracy of the Unix utility dc(1) can be checked by :echo ’82 43/25 43+65P80P82P73P76P32P70P79P79P76P10P’ | dc

May 1, 2022 · 9 min · jiezi

关于c++:CC气象数据中心实战手把手教你做工业级项目源码齐全

C/C++气象数据中心实战,手把手教你做工业级我的项目(源码齐全)超清原画 残缺无密 获取ZY:网盘链接hashCode() 和 equals()的区别equals()equals() 方法用于比较两个对象是否相等,它与 == 相等比较符有着本质的不同。 在万物皆对象的 Java 体系中,零碎把判断对象是否相等的权力交给程序员。具体的措施是把 equals() 方法写到 Object 类中,并让所有类继承 Object 类。 这样程序员就能在自定义的类中重写 equals() 方法, 从而实现自己的比较逻辑。 hashCode()hashCode() 的意义是哈希值, 哈希值是经哈希函数运算后失去的后果,哈希函数能够保障雷同的输出能够失去雷同的输入(哈希值),然而不能够保障不同的输出总是能得出不同的输入。 当输出的样本量足够大时,是会产生哈希冲突的,也就是说不同的输出产生了雷同的输入。 暂且不谈冲突,就雷同的输出能够产生雷同的输入这点而言,是及其宝贵的。它使得零碎只需要通过简略的运算,在工夫复杂度O(1)的情况下就能得出数据的映射关系,根据这种个性,散列表应运而生。 一种支流的散列表实现是:用数组作为哈希函数的输入域,输出值通过哈希函数计算后失去哈希值。而后根据哈希值,在数组种找到对应的存储单元。当发生冲突时,对应的存储单元以链表的形式保存冲突的数据。 两者关系在大多数编程实践中,归根结底会落实到数据的存取问题上。 在汇编语言期间,你需要老诚恳实地对每个数据操作编写存取语句。 而随着期间发展到明天,咱们都用更便利灵活的高级语言编写代码,比如 Java。 Java 以面向对象为中心思想,封装了一系列操作数据的 api,升高了数据操作的复杂度。 但在咱们对数据进行操作之前,首先要把数据按照肯定的数据结构保存到存储单元中,否则操作数据将无从谈起。 然而不同的数据结构有各自的个性,咱们在存储数据的时候需要抉择合适的数据结构进行存储。 Java 根据不同的数据结构提供了丰富的容器类,便利程序员抉择适合业务的容器类进行开发。 通过继承关系图咱们看到 Java 的容器类被分为 Collection 和 Map 两大类,Collection 又可能进一步分为 List 和 Set。 其中 Map 和 Set 都是不容许元素重复的,严格来说Map存储的是键值对,它不容许重复的键值。 值得注意的是:Map 和 Set 的绝大多数实现类的底层都会用到散列表结构。 讲到这里咱们提取两个关键字不容许重复和散列表结构, 回顾 hashCode() 和 equals() 的个性,你是否想到了些什么货色呢?equals()力不从心下面提到 Set 和 Map 不存放重复的元素(key),这些容器在存储元素的时必须对元素做出判断:在以后的容器中有没有和新元素雷同的元素? 你可能会想:这容易呀,间接调用元素对象的 equals() 方法进行比较不就行了吗? ...

May 1, 2022 · 1 min · jiezi

关于c++:C高性能网络服务保姆级教程-day02-真正的高并发还得看IO多路复用

教程阐明C++高性能网络服务保姆级教程 首发地址day02 真正的高并发还得看IO多路复用 本节目的应用epoll实现一个高并发的服务器 从单过程讲起上节从一个根底的socket服务说起咱们实现了一个根本的socket服务器,并留了个思考题 先启动server,而后启动一个client,不输出数据,这个时候在另外一个终端上再启动一个client,并在第二个client终端中输出数据,会产生什么呢?实际操作后,咱们会发现,在第二个client输出后,服务端并没有响应,直到第一个client也输出数据实现交互后,第二个client才会有数据返回。 这是因为服务端accept获取到第一个client的套接字后,因为第一个client未输出数据,所以服务端过程会阻塞在期待客户端数据那一行。 ...int read_num = read(accept_fd, read_msg, 100);...所以,第二个client实现三次握手后,连贯始终在服务端的全连贯队列中,期待accept获取解决。 多线程,一个线程一个连贯后续的client无奈失去解决是因为服务端只有一个线程,获取client套接字还有连贯通信全在一个线程中。 那咱们间接开多个线程就好了,主线程只负责accept获取客户端套接字。每来一个连贯,咱们就新起一个线程去解决客户端和服务端的通信。这样多个连贯之间就不会相互影响了。服务端程序如下: // per_conn_per_thread_server.cpp#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#include <thread>#include <arpa/inet.h>#include <string.h>#include <cstdio>#include <errno.h>void handleConn(int accept_fd) { char read_msg[100]; int read_num = read(accept_fd, read_msg, 100); printf("get msg from client: %s\n", read_msg); int write_num = write(accept_fd, read_msg, read_num); close(accept_fd);}int main() { int listen_fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); server_addr.sin_port = htons(8888); if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { printf("bind err: %s\n", strerror(errno)); close(listen_fd); return -1; } if (listen(listen_fd, 2048) < 0) { printf("listen err: %s\n", strerror(errno)); close(listen_fd); return -1; } struct sockaddr_in client_addr; bzero(&client_addr, sizeof(struct sockaddr_in)); socklen_t client_addr_len = sizeof(client_addr); int accept_fd = 0; while((accept_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_addr_len)) > 0) { printf("get accept_fd: %d from: %s:%d\n", accept_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); std::thread handleThread(handleConn, accept_fd); // 将线程设置为后盾线程,防止阻塞主线程 handleThread.detach(); }}应用thread库时,如果应用g++进行编译须要增加-lpthread,残缺编译命令: ...

April 27, 2022 · 4 min · jiezi

关于c++:C高性能网络服务保姆级教程-day01从一个基础的socket服务说起

首发地址:day01-从一个根底的socket服务说起教程阐明:C++高性能网络服务保姆级教程本节目的实现一个基于socket的echo服务端和客户端 服务端监听流程第一步:应用socket函数创立套接字在linux中,一切都是文件,所有文件都有一个int类型的编号,称为文件描述符。服务端和客户端通信实质是在各自机器上创立一个文件,称为socket(套接字),而后对该socket文件进行读写。 在 Linux 下应用 <sys/socket.h> 头文件中 socket() 函数来创立套接字 int socket(int af, int type, int protocol);af: IP地址类型; IPv4填AF_INET, IPv6填AF_INET6type: 数据传输方式, SOCK_STREAM示意流格局、面向连贯,多用于TCP。SOCK_DGRAM示意数据报格局、无连贯,多用于UDPprotocol: 传输协定, IPPROTO_TCP示意TCP。IPPTOTO_UDP示意UDP。可间接填0,会主动依据后面的两个参数主动推导协定类型#include <sys/socket.h>int sockfd = socket(AF_INET, SOCK_STREAM, 0);第二步:应用bind函数绑定套接字和监听地址socket()函数创立出套接字后,套接字中并没有任何地址信息。须要用bind()函数将套接字和监听的IP和端口绑定起来,这样当有数据到该IP和端口时,零碎才晓得须要交给绑定的套接字解决。 bind函数也在<sys/socket.h>头文件中,原型为: int bind(int sock, struct sockaddr *addr, socklen_t addrlen);sock: socket函数返回的socket描述符addr:一个sockaddr构造体变量的指针,后续会开展说。addrlen:addr的大小,间接通过sizeof失去咱们先看看socket和bind的绑定代码,上面代码中,咱们将创立的socket与ip='127.0.0.1',port=8888进行绑定: #include <sys/socket.h>#include <netinet/in.h>int sockfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr)); //用0填充server_addr.sin_family = AF_INET; //应用IPv4地址server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址;填入INADDR_ANY示意"0.0.0.0"server_addr.sin_port = htons(8888); //端口//将套接字和IP、端口绑定bind(server_addr, (struct sockaddr*)&server_addr, sizeof(server_addr));能够看到,咱们应用sockaddr_in构造体设置要绑定的地址信息,而后再强制转换为sockaddr类型。这是为了让bind函数能适应多种协定。 struct sockaddr_in{ sa_family_t sin_family; //地址族(Address Family),也就是地址类型 uint16_t sin_port; //16位的端口号 struct in_addr sin_addr; //32位IP地址 char sin_zero[8]; //不应用,个别用0填充};struct sockaddr_in6 { sa_family_t sin6_family; //(2)地址类型,取值为AF_INET6 in_port_t sin6_port; //(2)16位端口号 uint32_t sin6_flowinfo; //(4)IPv6流信息 struct in6_addr sin6_addr; //(4)具体的IPv6地址 uint32_t sin6_scope_id; //(4)接口范畴ID};struct sockaddr{ sa_family_t sin_family; //地址族(Address Family),也就是地址类型 char sa_data[14]; //IP地址和端口号};其中,sockaddr_in是保留IPv4的构造体;sockadd_in6是保留IPv6的构造体;sockaddr是通用的构造体,通过将特定协定的构造体转换成sockaddr,以达到bind可绑定多种协定的目标。 ...

April 27, 2022 · 2 min · jiezi

关于c++:c面经

语法层面static关键字的作用有哪些(润饰全局变量、润饰局部变量、润饰类的成员函数和数据成员)(扩大:name的两个独立的性质:存储周期storage duration 和 链接性 linkage)const关键字(润饰类型、润饰成员函数、润饰指针)语义层面指针和援用的区别是什么?c++11退出的右值援用、挪动语义、完满转发的含意内存相干2.1 new和malloc的区别,new做了什么new operator、operator new、placement new三者的作用和区别2.2 c++11内存治理,智能指针(shared_ptr、unique_ptr、enable_shared_from_this、weak_ptr)2.3 程序的内存调配(和操作系统联合起来)stl相干2.1 vectorpush_back的工夫复杂度(均摊剖析)push_back的强异样平安保障迭代器生效问题扩容问题2.2 map、set 红黑树2.3 unordered_map 哈希表基于对象初始化列表(必须应用:const成员、援用类型)成员函数(const、virtual、pure vritual)几个特地的成员函数(默认结构、拷贝、挪动、析构)面向对象封装:访问控制关键字继承:虚函数重写、override多态:虚函数机制、类型转换操作符重载、重写、暗藏的区别 多线程锁、条件变量、线程、原子变量友元相干friend

April 25, 2022 · 1 min · jiezi

关于c++:C-可变变量格式化字符串

一:格式化字符串#include <stdarg.h>...void ownLog(const char *fmt, ...){ va_list arglist; va_start(arglist, fmt); vprintf(fmt,arglist); { char log[1024];//格式化字符后存储的数组 vsprintf(log,fmt,arglist); } va_end(arglist);}main(){ ownLog("init data time(%d)",123);}在va_start到va_end之间能够获取到指定的数据 二、获取数据void ownLog(int count, ...){}

April 25, 2022 · 1 min · jiezi

关于c++:OneFlow-学习笔记从-Python-到-C-调用过程分析

撰文|月踏 在 OneFlow 中,从 Python 端咱们能够应用各种 Op 进行相干操作,上面是一个最最简略的 relu op 的应用示例: >>> import oneflow as of>>> x=of.tensor([-3,-2,-1,0,1,2,3], dtype=of.float)>>> of.relu(x)tensor([0., 0., 0., 0., 1., 2., 3.], dtype=oneflow.float32)尽管调用在 Python 端,但具体的实现是在 C++端,那么 OneFlow 是怎么样一步步从 Python 端调到 C++中的呢,本文以最最简略的 Relu 这个 Op 作为例子,来追溯一下在 OneFlow 中从 Python 端到 C++中的大抵调用过程,具体过程大略总结为 Python wrapper 和 C++ glue functor 两局部,上面是两局部的具体细节。 1 Python wrapperPython 的代码都在 python/oneflow 文件夹中,在剖析 Python wrapper 的过程中,也会波及很多 C++代码,次要是和 pybind11 绑定相干的,也一并归类到 Python wrapper 这部分了。 先看本文结尾示例中的 relu 接口的间接起源,在 python/oneflow/__init__.py 中能够找到上面这一行:from oneflow._C import relu能够看到 relu 是从_C 这个 module 中导出来的,所以持续看 oneflow/_C/__init__.py 这个文件: ...

April 24, 2022 · 3 min · jiezi

关于c++:C变量及方法命名

为了防止和C++保留字或者STL抵触,应尽量避免应用以下变量或办法命名,并应用: min -> mnmax -> mxsize -> szlength -> len(Python程序员可能感到不习惯)union -> merge(在并查集算法中)stack -> stkqueue -> que其余倡议应用的的常见命名还包含: ans(answer)res(result)cntsummididxflagst(state)dist(distance)

April 24, 2022 · 1 min · jiezi

关于c++:C11包含守卫ifndef预处理指令pragma-once操作符Pragma

蕴含守卫#ifndef通常用于放在头文件中,避免文件内容被屡次蕴含在同一个文件中: //---------------------------test.h begin-----------------------------#ifndef TEST_H#define TEST_H void test(); #endif//---------------------------test.h end-------------------------------//---------------------------main.cpp begin------------------------------- #include "test.h" //第一次被#include时,因为没有定义TEST_H,test.h的内容会被蕴含进来#include "test.h" //第二次被#include时,因为在第一次#include时曾经通过#define定义了TEST_H,所以test.h的内容不会被反复蕴含 //---------------------------main.cpp end---------------------------------这种形式的长处是:1.能够对文件内容进行部分管制。2.如果多个文件具备雷同文件内容,但文件名不同,那么蕴含守卫也能够胜利的防止屡次蕴含的问题。 这种形式的毛病是:1.蕴含守卫的名字要保障唯一性,否则如果不同文件用了雷同的蕴含守卫,会导致只有一个文件被真正的蕴含进来。2.因为是方生在预编译期间,须要关上文件能力对蕴含守卫进行判断,所以编译的工夫会稍长。 预处理指令#pragma once定义在文件中,可批示编译器,这个文件只能被编译一次: #pragma once void test();这种形式的长处是:1.因为只被编译一次,所以编译速度较快。 这种形式的毛病是:1.不能对文件的部分内容进行管制,只能对文件整体管制。2..如果多个文件具备雷同文件内容,但文件名不同,那么尽管每个文件都只会被编译一次,但雷同的文件内容,会呈现反复定义的编译谬误: //---------------------------human1.h begin-----------------------------#pragma once struct Human{ std::string name; int age;}; struct Human xiaoming = {"xiaoming", 10}; //---------------------------human1.h end-------------------------------//---------------------------human2.h begin-----------------------------#pragma once struct Human{ std::string name; int age;}; struct Human xiaoming = {"xiaoming", 10}; //---------------------------human2.h end-------------------------------//---------------------------main.cpp-----------------------------#include <string>#include "human1.h"#include "human2.h" using namespace std; int main(){ return 0;} //---------------------------main.cpp end------------------------------- 因为human1.h和human2.h都定义了struct Human,所以编译时会报错:redefinition of 'struct Human'因为human1.h和human2.h都定义了xiaoming,所以编译时会报错:redefinition of 'Human xiaoming'操作符_PragmaC++11反对了操作符_Pragma,_Pragma("once")的成果与#pragma once雷同,不过因为_Pragma是操作符,所以能够利用于宏定义中: ...

April 11, 2022 · 1 min · jiezi

关于c++:Leetcode刷题股票问题系列总结

1. 交易股票的最佳时机给定一个数组 prices ,它的第 i 个元素 prices[i] 示意一支给定股票第 i 天的价格。你只能抉择 某一天 买入这只股票,并抉择在 将来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你能够从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。 int maxProfit(vector<int>& prices) { int min_price = INT_MAX, max_profit = 0; for(auto price : prices) { max_profit = max(max_profit, price - min_price); min_price = min(min_price, price); } return max_profit;}工夫复杂度:O(n),只须要遍历一次。空间复杂度:O(1),只应用了常数个变量。 2. 交易股票的最佳时机 II给定一个数组 prices ,其中 prices[i] 示意股票第 i 天的价格。在每一天,你可能会决定购买和/或发售股票。你在任何时候 最多 只能持有 一股 股票。你也能够购买它,而后在同一天发售。返回你能取得的最大利润 。 解法一:动静布局思考到「不能同时参加多笔交易」,因而每天交易完结后只可能存在手里有一支股票或者没有股票的状态。 定义状态dp[i][0]示意第 i 天交易完后手里没有股票的最大利润,dp[i][1]示意第i天交易完后手里持有一支股票的最大利润(i从0开始)。 思考dp[i][0]的转移方程,如果这一天交易完后手里没有股票,那么可能的转移状态为前一天曾经没有股票,即dp[i-1][0],或者前一天完结的时候手里持有一支股票,即dp[i-1][1],这时候咱们要将其卖出,并取得price[i]的收益。因而为了收益最大化,咱们列出如下的转移方程: dp[i][0] = max{dp[i-1][0], dp[i-1][1]+prices[i]} 再来思考dp[i][1],依照同样的形式思考转移状态,那么可能的转移状态为前一天曾经持有一支股票,即dp[i−1][1],或者前一天完结时还没有股票,即dp[i−1][0],这时候咱们要将其买入,并缩小prices[i]的收益。能够列出如下的转移方程: dp[i][1] = max{dp[i-1][1], dp[i-1][0]-prices[i]} 对于初始状态,依据状态定义咱们能够晓得第 00 天交易完结的时候 dp[0][0]=0,dp[0][1]=−prices[0]。 ...

April 8, 2022 · 4 min · jiezi

关于c++:CS111-EIE111

Homework 1 : Knowledge items of C++ (part 1)C++ : CS111 EIE111 LP104MUST 2021 SpringInstructor: Zhiyao LiangMarch 22 2021I. Purpose of the homeworkIn order to write a good program, you need to know the following(a) The target tasks:The problems to be solved, the requirements and constraints.(b) The proper computation process for the taskThe algorithms.The data structure.(c) Enough knowledge of the programming language.So that the computation process can be implement as a program.There other homeworks that will emphasize the part (a) and (b). This homework emphasizes on part (c), and it will test different knowledge items(KI). The approach is based on the following observation:A knowledge item (KI) can be described or tested by at least two ways:Asking and answering some questions.Doing some tasks that are related to the KI.II. Requirements of the homeworkWrite a C++ program that satisfy two aspects of requirements:A: Use the C++ style as much as possibleIf there are different ways to write the code, choose the C++ way, not the C way. For example:For input and output, use cout and cin , instead of printf() and scanf() .Include the head file cstring in stead of string.h .B: Implement each task descried in Section IVSection IV describes a sequence of numbered tasks. Each task requires writing some simple code to reflect your understanding of someknowledge items of C++.For each task, say the nthtask, in your program you should the write some comment of the form / <n> / besides the statements thatimplement the KP.If a task can be implemented by several different pieces of code in the program, the comment mentioning a task number only needs to appearonce in the program. .For example, for the 5threquirement :5: Declare a variable of type int .The corresponding code that cover this knowledge point in the program could be like the following:int x; / <5> /If there are 3 statements declaring integer variables in the, the comment / <5> / only needs to appear once in your program.If a piece of code can cover several tasks, then the task numbers can be mentioned together. For example, if a statement that can cover the tasks4 and 6, the its comment can look like:/ <4> <6> /// some statementIII The knowledge neededThe tasks will cover the knowledge aspects covered from chapter 1 to chapter 9 in the textbookThese tasks cover the knowledge points of C++ in the following aspects:Compile programs of C++, C++ 2011 at command line.Structure of a program. Relationships between .cpp and .h files.The proper content of head files and the .cpp files.How to use the names defined in other files.Data types, constants, variables, arrays.composite data types:struct, union, enumVariable and array initializationHow to create data storage on different memory sectionsstatic areastackheap (allocation and release)pointers and referencesFunction definition, call, parameters, argumentsAn array name as an argument of function callsRecursive functionThree loop statementsnew style of for statements in C++if, if-else statementsswitch statementsinput and outputcin and coutknow the status of previous inputclear input queuereading and writing files.name spaces.template functionsDefine functions to solve simple computation problemsIV TasksThis section describe a list of tasks that need to be fulfilled in the program. For some tasks, their related knowledge items (marked by [k]), hints todo it ( [hint] ), and the design ideas ( [design] ) are mentioned. ...

April 4, 2022 · 14 min · jiezi

关于c++:网格拟合

这里的网格拟合,当然是三维网格拟合。 三维网格拟合有什么用?呃.....当前再说吧...... 什么是网格拟合嗯,常常常常听到[拟合]这个名词,它示意一个动作。最常听到的是最小二乘拟合---把一系列点拟合出一条线---把三维空间散乱点拟合出一个立体、球面、柱面... 拟合,总须要一个拟合源,总要有一个指标。下面场景中,拟合源个别是二维或者三维的点数据,指标个别是线、立体、球面或者柱面等等的数学参数示意。 OK,大略曾经晓得拟合是做什么的了。那咱们的三维网格拟合,又是怎么回事呢? 其实,三维网格的拟合和上述所谓拟合并没有本质区别,只是数据源和拟合指标都是可任意的三维网格数据而已,将两个三维网格拟合,其后果依然是一个三维网格,只不过拟合后的后果网格可能带有源数据和指标数据的局部显著特色。用公式示意就是: Mesh A + Mesh B = Mesh C,其中 “+”示意拟合计算留神:上述所谓三维网格的拟合,并不蕴含网格带纹理的状况。即纹理不参加拟合运算。 说白了,所谓三维网格的拟合,其实就是多个三维网格通过肯定的 ‘’ 修修剪剪 ‘’ 产生一个新网格的过程,新网格就是拟合的后果。 怎么进行网格拟合哦,我曾经晓得了什么是网格拟合,但怎么进行网格拟合计算呢。 如果,我有A和B两个三维网格数据,网格A有10w点,30w三角面片,网格B有7w点,20w三角面片,额(⊙﹏⊙)....它俩应该怎么进行拟合计算呢?---我应别离取A或B的哪一部分加入计算呢?A和B不在同一个坐标系下怎么办呢?我的拟合运算会不会扭转A或者B的三角网格顶点之间的连贯关系呢?A和B体积相差太大(比方一只狗和一只猫)怎么办呢?须要缩放吗?缩放系数怎么解决呢?拟合品质如何评估呢?......呃呃...头好大.... 既然头好大,那就规定非凡场景吧。 场景还是来拿手头的人头网格说事。首先,人头点云,隐含了点云的体积头差不多(小孩子除外);其次,同一个扫描设施获取的三维人头网格数据量不会差异太大(其实这个条件没啥影响);最初,就是...我手头只有三维人头数据能够测试(么有去找更多的)。 有上面两组数据,其中上边的图像记为Mesh A,下边的记为Mesh B, Mesh A:只有实在人脸局部,网格和顶点数量较多,三角网格之间并不是很“顺滑”;Mesh B:虚构全人头网格,网格数目和顶点数绝对A来说较少,且mesh表面光顺性较好。 指标,将A和B拟合,结构带有实在人脸网格模型的三维人头(理论利用中是有重要意义的)。 简略拟合至此,可能很多很多敌人,曾经想到了一种非常简单的网格拟合办法。怎么做呢? 首先,将Mesh A和Mesh B初步对齐,行将两个网格人脸局部对齐,放在同一个坐标系下。如何对齐呢?很简略,因为Mesh A和Mesh B都示意人脸网格,则其面部必有独特特色---眼睛、鼻子、嘴巴、鼻梁、眉毛.....通过选两组Mesh中对应的特色点,基于指定的准确的对应点对,通过ICP计算,即可取得某Mesh的变换矩阵,从而使得两个Mesh对立到对立坐标系下。示意图如下: 其次,在实现上述初步对齐--即两个模型的眼睛对眼睛、鼻尖对鼻尖...后,咱们只有扭转Mesh B的面部网格构造形态即可。通过设定脸部间隔阈值,在保障Mesh B各个顶点链接关系不变的条件下(即不扭转拓扑关系),扭转Mesh B的脸部特色点的网格顶点坐标,使得Mesh B脸部出现Mesh A的外观特色,即实现了两个网格的拟合。 如何实现上述计算呢?最简略的---置换或者说替换。通过设定的间隔阈值,找到Mesh B和Mesh A的脸部对应点对,将两个Mesh的对应点对的坐标间接进行替换,同时保障Mesh B中点的链接关系不变(若该边,可能 “ 脸就不是脸了 ”)。如下图: 能够看到,基于【简略拟合】实践,根本能够两个网格的拟合,并能根本失去本人想要的后果---含有实在人脸形态的全人头网格模型。 这就够了吗? 危险显然不够!其实,上边的【简略拟合】存在较大的危险,其后果根本无奈利用在理论生产我的项目中。 危险点1:品质较差。以上述形式拟合网格模型,如上图边界局部所示,拟合后果存在较大的突起,有十分突兀的形态变动。 危险点2:精度无奈保障。其实上述形式中,只是简略的对应点的顶点替换,这就导致了在替换时,各个参加计算的点没有思考其邻域点的散布状况。计算过程中,极大概率导致某个特色点的坐标屡次变换,而且该特色点的坐标只与最初一次变动(最初一个对应点)无关---因为,Mesh B和 Mesh A的点数、网格数目及点密度都不一样,当将两个网格拟合计算时,必然存在一对多或者多对一的状况。 危险点3:尺寸差异较大。这个问题应该怎么看待呢?!理论中,相对没有两个一摸一样的人,那么尺寸必然存在肯定误差。那咱们只能尽可能的缩小这种网格尺寸上的误差,可见,在下面计算中,没有思考这一点。 ...... 当然,还有其余很多的危险点,本人也无奈一一穷举。总之,上述形容计划兴许会是一种网格拟合的解决方案,然而对网格的后处理工作减少了许多的难度,须要更进一步的钻研与改良。 ...... 有没有其余方法呢? 实现有!先上一篇论文 《Review of Statistical Shape Spaces for 3D Data with Comparative Analysis for Human Faces》. ...

April 2, 2022 · 1 min · jiezi

关于c++:CC气象数据中心实战手把手教你做工业级项目附带源码

download:C/C++气象数据中心实战,手把手教你做工业级我的项目附带源码复制下崽ZY:https://www.zxit666.com/2347/大家在应用IDEA开发的时候有没有留神到过一个提醒,在字段上应用Spring的依赖注入注解@Autowired后会呈现如下正告 Field injection is not recommended (字段注入是不被举荐的) 然而应用@Resource却不会呈现此提醒网上文章大部分都是介绍两者的区别,没有提到为什么,过后想了良久想出了可能的起因,明天来总结一下Spring常见的DI形式 结构器注入:利用构造方法的参数注入依赖Setter注入:调用Setter的办法注入依赖字段注入:在字段上应用@Autowired/Resource注解 @Autowired VS @Resource事实上,他们的基本功能都是通过注解实现依赖注入,只不过@Autowired是Spring定义的,而@Resource是JSR-250定义的。大抵性能基本相同,然而还有一些细节不同: 依赖辨认形式:@Autowired默认是byType能够应用@Qualifier指定Name,@Resource默认ByName如果找不到则ByType实用对象:@Autowired能够对结构器、办法、参数、字段应用,@Resource只能对办法、字段应用提供方:@Autowired是Spring提供的,@Resource是JSR-250提供的 各种DI形式的优缺点参考Spring官网文档,倡议了如下的应用场景: 结构器注入:强依赖性(即必须应用此依赖),不变性(各依赖不会常常变动)Setter注入:可选(没有此依赖也能够工作),可变(依赖会常常变动)Field注入:大多数状况下尽量少应用字段注入,肯定要应用的话, @Resource绝对@Autowired对IoC容器的耦合更低 Field注入的毛病 不能像结构器那样注入不可变的对象依赖对外部不可见,外界能够看到结构器和setter,但无奈看到公有字段,天然无奈理解所需依赖会导致组件与IoC容器紧耦合(这是最重要的起因,来到了IoC容器去应用组件,在注入依赖时就会十分困难)导致单元测试也必须应用IoC容器,起因同上依赖过多时不够显著,比方我须要10个依赖,用结构器注入就会显得宏大,这时候应该考虑一下此组件是不是违反了繁多职责准则 为什么IDEA只对@Autowired正告Field注入尽管有很多毛病,但它的益处也不可疏忽:那就是太不便了。应用结构器或者setter注入须要写更多业务无关的代码,非常麻烦,而字段注入大幅简化了它们。并且绝大多数状况下业务代码和框架就是强绑定的,齐全松耦合只是一件现实上的事,就义了麻利度去适度谋求松耦合反而得失相当。那么问题来了,为什么IDEA只对@Autowired正告,却对@Resource熟视无睹呢?集体认为,就像咱们后面提到过的: @Autowired是Spring提供的,它是特定IoC提供的特定注解,这就导致了利用与框架的强绑定,一旦换用了其余的IoC框架,是不可能反对注入的。而 @Resource是JSR-250提供的,它是Java规范,咱们应用的IoC容器该当去兼容它,这样即便更换容器,也能够失常工作。

April 2, 2022 · 1 min · jiezi

关于c++:C语言利用指向数组的指针变量或指针数组求输入的数组的各行和

1、例如输出:2 3 4          5 6 7 输入:9          182、残缺代码如下2.1 C++版本#include <iostream>#include <cstring>using namespace std;int a[2][3];int res[2];void Sum(int (*p)[3], int total[], int n){ for(int i = 0; i < n; i++) { for(int j = 0; j < 3; ++j) total[i] += p[i][j]; }}int main(){ for(int i = 0; i < 2; ++i) for(int j = 0; j < 3; ++j) cin >> a[i][j]; Sum(a, res, 2); for(int i = 0; i < 2; ++i) cout << res[i] << endl; return 0; }2.2 C语言版本#include <stdio.h>int a[2][3];int res[2];void Sum(int(*p)[3], int total[], int n){ for (int i = 0; i < n; i++) { for (int j = 0; j < 3; j++) total[i] += p[i][j]; }}int main(){ for (int i = 0; i < 2; i++) for (int j = 0; j < 3; j++) scanf_s("%d", &a[i][j]); Sum(a, res, 2); for (int i = 0; i < 2; i++) printf("%d\n", res[i]); return 0;}3、截图 ...

April 2, 2022 · 1 min · jiezi

关于c++:CS111问题求解

Homework 1 : Knowledge items of C++ (part 1)C++ : CS111 EIE111 LP104MUST 2021 SpringMarch 22 2021I. Purpose of the homeworkIn order to write a good program, you need to know the following(a) The target tasks:The problems to be solved, the requirements and constraints.(b) The proper computation process for the taskThe algorithms.The data structure.(c) Enough knowledge of the programming language.So that the computation process can be implement as a program.There other homeworks that will emphasize the part (a) and (b). This homework emphasizes on part (c), and it will test different knowledge items(KI). The approach is based on the following observation:A knowledge item (KI) can be described or tested by at least two ways:Asking and answering some questions.Doing some tasks that are related to the KI.II. Requirements of the homeworkWrite a C++ program that satisfy two aspects of requirements:A: Use the C++ style as much as possibleIf there are different ways to write the code, choose the C++ way, not the C way. For example:For input and output, use cout and cin , instead of printf() and scanf() .Include the head file cstring in stead of string.h .B: Implement each task descried in Section IVSection IV describes a sequence of numbered tasks. Each task requires writing some simple code to reflect your understanding of someknowledge items of C++.For each task, say the nthtask, in your program you should the write some comment of the form / <n> / besides the statements thatimplement the KP.If a task can be implemented by several different pieces of code in the program, the comment mentioning a task number only needs to appearonce in the program. .For example, for the 5threquirement :5: Declare a variable of type int .The corresponding code that cover this knowledge point in the program could be like the following:int x; / <5> /If there are 3 statements declaring integer variables in the, the comment / <5> / only needs to appear once in your program.If a piece of code can cover several tasks, then the task numbers can be mentioned together. For example, if a statement that can cover the tasks4 and 6, the its comment can look like:/ <4> <6> /// some statementIII The knowledge neededThe tasks will cover the knowledge aspects covered from chapter 1 to chapter 9 in the textbookThese tasks cover the knowledge points of C++ in the following aspects:Compile programs of C++, C++ 2011 at command line.Structure of a program. Relationships between .cpp and .h files.The proper content of head files and the .cpp files.How to use the names defined in other files.Data types, constants, variables, arrays.composite data types:struct, union, enumVariable and array initializationHow to create data storage on different memory sectionsstatic areastackheap (allocation and release)pointers and referencesFunction definition, call, parameters, argumentsAn array name as an argument of function callsRecursive functionThree loop statementsnew style of for statements in C++if, if-else statementsswitch statementsinput and outputcin and coutknow the status of previous inputclear input queuereading and writing files.name spaces.template functionsDefine functions to solve simple computation problemsIV TasksThis section describe a list of tasks that need to be fulfilled in the program. For some tasks, their related knowledge items (marked by [k]), hints todo it ( [hint] ), and the design ideas ( [design] ) are mentioned. ...

March 31, 2022 · 14 min · jiezi

关于c++:多视角三维模型纹理映射-03

首先,严格意义来说,本文题目并非合乎无关多视角纹理映射的相干内容,而是基于上一篇文章《多视角三维模型纹理映射 02》的留坑持续... 其实,应该叫做 -- 3D扫描仪转台标定 吧。 在开启这部分的工作前,查阅了很多论文、材料等,其中比拟有借鉴意义的是《旋转平台点云数据的配准办法》,【作者周朗明,郑顺义,黄荣永,武汉大学】,这篇文章给了本人极大的启发。 设施与筹备先来看一些本人所用到设施及其大体组合构造示意图: 本人所应用的根本设施如上图所示:相机支架,深度相机(间接产生点云,内参已知)、旋转平台,待测物体(标定块)。嗯嗯,只有也仅有上述几个设施而已。其中旋转平台和相机的间隔应在正当范畴内。 在固定好上述设施的地位关系后,接下来就是设计标定算法并验证了。 3D扫描仪转台标定算法设计首先要明确,标定的目标是什么,料想的标定后果是什么。 标定目标第一个问题:标定的目标??目标难道不是确定转台和相机的绝对地位关系嘛?!是,当然是。更进一步的,因为相机无奈间接拍摄转台外表获取相应数据(此处转台为纯彩色,且转台外表没有标记点),因而须要借助标定块来实现相应目标。此时,上图中 [实物 ]能够临时了解为 [标定块 ]。 此时,又引来另一个问题,抉择什么样的标定块。留神,这里的标定块,是【块】,不是标定板,是一个三维的实体规范块。在抉择标定块时候,最好该标定块有严格且已知的规范尺寸,形态最好比较简单,且数学意义上比拟好形容,如球、圆柱等等。 算了,间接上我选的标定块吧,如图: 对,没有错。我抉择了台球,台球简直合乎上述所有要求(规范直径,规范数学形容公式、易拟合),而且还比拟便宜。此时标定块或者称为标定球更为适合。在理论施行中,我抉择了那个纯白色的球球...eee...因为其外表色调比拟繁多.... 留神:因为相机内参曾经晓得了,不须要对深度相机进行反复标定,所以也不须要标定板。 至此,根本解决了所有内部依赖条件。 标定的后果在筹备得当所有的内部硬件条件后,进一步便须要寻求标定后果。 设想一下扫描过程:转台在地位1,相机拍摄该地位下的标定块点云1-1;转台在地位2,相机拍摄该地位下的标定块点云2-2;...如此循环直到实现标定块的360度扫描。 转台旋转一周,拍摄的台球点云如下图: 不言而喻,“貌似”规范球在围绕一个货色旋转了一周。想想也是如此,不就是转台带着规范球转了一圈嘛。 的确,这里的一个货色就是咱们3D转台标定要求解的货色。从论文和上图数据,不难猜测:扫描失去的点云,是在绕某个固定轴--这个货色旋转。至此,根本晓得,我要求解的后果应该是个固定轴。 是什么样的固定轴呢?--旋转平台的核心轴---旋转平台的核心轴在相机坐标系下的示意---旋转平台的中心点和旋转平台的立体法向量 在相机坐标系下的示意==>标定后果。 至此,彻底明确了,所谓的标定后果,应该蕴含两个数据:点坐标和向量。 在上述场景下,如何求解这两个货色?!根本求解过程如下: 将台球固定在转台表明,管制旋转平台绕固定角度旋转;相机拍摄每个固定角度下的台球点云数据;为缩小误差,步骤1和步骤2数据量个数越多越好;拟合每个角度下的台球点云---球数据,并提取球心(提取球半径,与标准台球半径比拟,侧面测验规范球拟合算法精度);反复步骤4,直至计算出所有拍摄角度下的球心坐标;基于步骤5,在三维空间中拟合圆;提取三维圆形的圆心和法向量==>标定后果。为了进一步提高精度,能够反复步骤1--7,取屡次测量后果的均值作为最终的标定后果。 测试将规范球的标定后果利用于规范球,试验后果如下: 由上图可见,标定过程根本正确,后果根本可承受。 测试人头数据: 本篇文章的记录根本都可能基于PCL实现,所以不再贴源码。 大节本篇文章联合后面几篇,实践上根本能够搭建一个转台式三维扫描仪,当然,还有很多很多中央须要改良。 最近一系列文章涵盖了3D标定(本文)、点云非线性全局优化、全局点云交融、三维网格模型纹理映射等几个方面的根本要点及基础理论。尽管目前都已实现,但还有待更进一步的深刻开掘。

March 31, 2022 · 1 min · jiezi

关于c++:CS-120-C项目

CS 120 Module 1 Open-Ended Project: Style and ErrorsDue on Gradescope by 11:59pm ET on Friday, February 19thFor this project, you will create two differently-styled versions of a creative C++ class on GitHub and will document the bugs you found in the code.Requirements ? All of your programming files should be in a private GitHub repository in the course organization. Your repository must be named with the convention: M1OEP-Style-Errors-netid, where netid is your UVM NetID username.The repository should have a .gitignore file and a README file (see the GitHub-with-CLion repo for directions).? Your C++ class must have at least two private fields and at least four methods. ? Your class should be nontrivial: at least one method must not be a constructor, getter, setter, or destructor. ? Your class declaration should be in a header file and the implementation in a corresponding .cpp file.? You must use objects of the class to create a fully functioning program in a main.cpp file. Describe your program in your README file.? Your two style versions should be stored in different branches of your repository.? Your README must describe which of the two styles you like better and why. ? The README file must also detail at least three errors that you experienced while developing this project.At least one must be a compiler error and at least one must not.For each bug, explain what you did to fix it.At least one of these explanations should include the use of the debugger.? All of the above must be pushed to your GitHub repository. ? On Gradescope, submit the URL of the repository. The last commit to each branch will be graded. If you have more than two branches, clarify which ones should be graded in the master branch README file.Design Your two style versions must include the following (you can choose how to split the options between the two versions, and each version should have consistent style within itself):Hanging and Egyptian-style bracesCamel case and snake caseTop-of-file comments and method commentsVariables with and without prefixesFor details on these, see the M1GP-Style-Me repository README file.Grading The project is out of 50 points. 5 pts Project compiles and runs. GitHub repository set up as described above. 5 pts Class satisfies requirements described above.pts Style 1 satisfies requirements and is consistent throughout the files.pts Style 2 satisfies requirements and is consistent throughout the files.pts The main program is fully functional.pts The README file contains all that is described above.如

March 29, 2022 · 2 min · jiezi

关于c++:DeepRoute-Lab-C性能CPU-Cache-Serial-1

性能C++,作为最艰涩、最难把握的支流编程语言,一贯是容易上手,却很难写好。而这难写好的局部中,除了代码格调等稍微形象的局部,最难也最容易忽略的局部则是性能了。依据经典的二八准则,通常20%左右的代码耗费了80%左右的性能。然而,用户日常接触到的性能、或者在日常应用的场景下,性能是能够满足的,因而这往往造成程序员的漠视并埋下了隐患。 通常状况下,一旦遇到性能问题,那将是比性能问题更辣手、更难解决的。 C++,作为常常和硬件间接打交道的高级语言,性能问题堪称是重灾区。本系列文章,将联合实践和实际,深度分析典型的性能问题和陷阱。 在上一篇性能专题的文章(点击可跳转上期文章)中,咱们具体地介绍了C++代码中的性能杀手【拷贝】,并提供了几类具备针对性的应答措施。然而作为须要时刻思考硬件条件的编程语言,如果你认为防止了不必要的结构和拷贝,就能够领有极致的性能的话,那就大错特错了。 让咱们来看一个与拷贝无关,然而又存在显著性能问题的例子。 举例 CPU Cache首先咱们须要介绍一下什么是CPU Cache。 在咱们写代码的时候,有3个计算机硬件和咱们关系密切,别离是CPU、内存和硬盘。为什么这样说呢?因为咱们敲的代码和编译进去的执行文件是存储在硬盘上的,每次程序启动,对应的数据和代码被加载进内存,而后各种各样的指令会在CPU中运行。 看似内存中的数据会被间接加载进CPU进行解决,而后这两头实际上还存在着一个至关重要的组件:缓存(CPU Cache)。缓存通常会存储着最近拜访过的内存中的数据(这就是大家相熟的LRU、LFU等缓存替换算法作用的中央),它领有远快于内存(RAM)的访问速度,然而容量也显著地小于内存,它能够被视作CPU和内存数据的桥梁。 同时,CPU Cache也有不同的品种,次要有D-Cache,I-Cache和TLB。其实只有晓得全名,就很好了解了。D-Cache全名data cache,用来缓存数据。I-Cache全名instruction cache,用来缓存CPU指令。TLB全名translation lookaside buffer,用来缓存虚拟内存到物理内存的映射后果。 TLB看似让人摸不着头脑,然而有一个好消息是:如果D-Cache和I-Cache可能被很好地利用,那么TLB的性能通常也能从中受害。 I-Cache呢,在小片代码中区别不会太大,而且编译器会帮忙做肯定的优化,因而咱们最首要思考的就是D-Cache,它和咱们写代码的形式具备最严密的分割。 以一个6核12线程CPU为例, Cache的构造大抵如下: 能够看到,每个物理外围领有2个硬件线程,每个线程领有本人的L1 Cache,每个外围领有本人的L2 Cache,所有外围共享L3 Cache和内存。(请记住这个构造,前面的剖析都会基于此) 那么,这些CPU Cache具体是怎么影响咱们代码的性能的呢? 前文中咱们提到了,CPU Cache是CPU和内存之间的桥梁并且领有多个档次,可能此时咱们曾经发现,如果每一级缓存领有不同的访问速度,是不是就会导致拜访同样的数据(这些雷同的数据可能因为之前的拜访形式坐落于不同级的缓存和内存中)耗费不同的工夫?答案是必定的,下图中能够看到一个典型的古代CPU各个硬件的访问速度。能够看到,L1 Cache的访问速度根本是内存的100倍以上,L2 Cache则是10倍以上。 因而,整体上来看,越高的缓存命中率意味着程序具备越高的性能。所谓缓存命中率,直白地说,就是指原本要去内存中读取的数据,正好存在于缓存中的比例。 那么,是什么样的起因会导同样的数据在不同的拜访模式下会坐落于不同层级的缓存中呢?这就不得不提到缓存的存储形式和根本单元了。 CPU Cache的根本单元叫做cache line,这些cache line中存储的就是内存中的hottest data。内存和Cache替换数据都是通过它。对于典型的古代处理器,cache line的大小通常都是64 bytes,意味着,每一条cache line能够存储8个64位的整型。到目前为止,所有看上去都那么失常。 然而,cache line有一个十分非凡的性质,就是它的读写必须操作一整条!比方,你只想读前8个bytes,对不起,不行,整条cache line都会被读取;你只想写最初8个bytes,对不起,不行,整个cache line都须要更新。 缓存局部性(Cache locality)有了下面对于CPU Cache的介绍,咱们能够剖析为什么例1中拜访二维数组的形式会对性能有如此大的影响了。以下剖析咱们思考冷启动的模式,意即缓存最开始是空的,外面没有任何数据。 留神到,咱们的二维数组中存储的数据类型为整型,每个元素的大小为8 bytes,因而一条大小为64 bytes的cache line能够存储8个数据。 如果咱们一行一行地拜访二维数组数组,第一次读取缓存的某条cache line的时候,数据不在缓存上,须要从内存中读取,因而这次是一次cache miss,CPU读取这条数据的耗时是 t_memory + t_cache。然而请留神,因为cache line的个性,它的操作必须是整条的,因而在t_memory 的这次耗费中,在内存上相邻的另外7个int64型的数据也被加载到了这条cache line中。因为咱们是按行读取,前面拜访的7个数据正好就是被加载进了cache line的数据,他们的读取工夫都只须要t_cache,省去了7次t_memory 的高额开销。 在这种状况下,每读取8个元素的总工夫开销就是 t_memory + 8 t_cache。以上图中的硬件为例,仅思考L2 Cache,即100 + 8 7 = 156ns。 ...

March 28, 2022 · 1 min · jiezi

关于c++:CC气象数据中心实战手把手教你做工业级项目吾爱fen享

前言:download:C/C++气象数据中心实战,手把手教你做工业级我的项目吾爱 复制下载资源课程:https://www.97yrbl.com/t-991.htmlc语言入门C语言一经呈现就以其功能丰富、表达能力强、灵便不便、利用面广等特点迅速在全世界遍及和推广。C语言岂但执行效率高而且可移植性好,能够用来开发应用软件、驱动、操作系统等。C语言也是其它泛滥高级语言的鼻祖语言,所以说学习C语言是进入编程世界的必修课。 hello,world#include<stdio.h> int main(){ /*在双引号两头输出Hello World*/ printf("Hello World"); return 0; }注:在最新的C规范中,main函数前的类型为int而不是void c语言的具体构造简略来说,一个C程序就是由若干头文件和函数组成。 mark #include <stdio.h>就是一条预处理命令, 它的作用是告诉C语言编译系统在对C程序进行正式编译之前需做一些预处理工作。函数就是实现代码逻辑的一个小的单元。必不可少之主函数一个C程序有且只有一个主函数,即main函数。 markC程序就是执行主函数里的代码,也能够说这个主函数就是C语言中的惟一入口。而main后面的int就是主函数的类型.printf()是格局输入函数,这里就记住它的性能就是在屏幕上输入指定的信息return是函数的返回值,依据函数类型的不同,返回的值也是不同的。\n是转义字符中的换行符。(留神:C程序肯定是从主函数开始执行的)良好习惯之标准一个阐明或一个语句占一行,例如:蕴含头文件、一个可执行语句完结都须要换行。函数体内的语句要有显著缩进,通常以按一下Tab键为一个缩进。括号要成对写,如果须要删除的话也要成对删除。当一句可执行语句完结的时候开端须要有分号。代码中所有符号均为英文半角符号。mark程序解释——正文正文是写给程序员看的,不是写给电脑看的。 C语言正文办法有两种: `多行正文: / 正文内容 /单行正文: //正文一行` 有名有姓的C(标识符)C语言规定,标识符能够是字母(A~Z,a~z)、数字(0~9)、下划线_组成的字符串,并且第一个字符必须是字母或下划线。在应用标识符时还有留神以下几点: 标识符的长度最好不要超过8位,因为在某些版本的C中规定标识符前8位无效,当两个标识符前8位雷同时,则被认为是同一个标识符。标识符是严格辨别大小写的。例如Imooc和imooc 是两个不同的标识符。标识符最好抉择有意义的英文单词组成做到"见名知意",不要应用中文。标识符不能是C语言的关键字。想理解更多C语言关键字的常识。变量及赋值变量就是能够变动的量,而每个变量都会有一个名字(标识符)。变量占据内存中肯定的存储单元。应用变量之前必须先定义变量,要辨别变量名和变量值是两个不同的概念。 mark变量定义的个别模式为:数据类型 变量名;多个类型雷同的变量:数据类型 变量名, 变量名, 变量名...;mark留神:在定义中不容许间断赋值,如int a=b=c=5;是不非法的。 变量的赋值分为两种形式: 先申明再赋值申明的同时赋值根本数据类型C语言中,数据类型可分为:根本数据类型结构数据类型指针类型空类型四大类

March 27, 2022 · 1 min · jiezi