关于c++:TCP-IP网络编程学习笔记

根本数据结构和函数示意IPv4地址的构造体:struct sockaddr_in{ sa_family_t sin_family; //示意地址族 uint16_t sin_port; //示意16位的端口号(包含TCP和UDP) struct in_addr sin_addr; //32位的ip地址 char sin_zer[8] ; //不应用 };对于in_addr:struct in_addr{ In_addr_t s_addr;//32位IP地址}对于下面定义的成员变量类型,大部分都是在POSIX外面定义好了的,属于跨平台可移植的根本数据类型的别名。 对于sockaddr_in成员变量的剖析: sin_family: 对于每种协定实用于不同的地址族。典型的有: AF_INET : IPv4协定应用的地址族AF_INET6 : IPv6协定应用的地址族AF_LOCAL : 本地通信sin_port: 以网络字节序列保留端口号sin_zero: 字节填充符,无非凡的含意。对于socket过程须要绑定socket地址。对应的函数是bind 具体用法: bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr));这里须要留神的是struct sockaddr*这个数据结构。在原先老版本的unix网络通信中并没有sockaddr_in这个数据结构,只有sockaddr struct sockaddr { sa_family_t sin_family; char sa_data[14]; //地址信息} 留神这里的sa_data数组蕴含了sockaddr_in数据结构中前面的所有信息,包含端口号、IP地址等等,这样的结果是编程起来十分不不便。所以前面把这个数据结构转换为了sockaddr_in,但同时也保障了字节序列和这个数据结构统一。因而这里即使应用了强制类型转换也不会影响数据的含意。 网络字节序列因为不同的机器CPU采纳的存储策略也不同。有些采纳大端法,有些采纳小端法。为了放弃在不同机器之间进行网络通信数据格式的对立,网络序列对立采纳大端法。所以在小端法的机器上发送数据时,首先要转换为大端法。对应的零碎API: unsigned short htons(unsigned short);//htons:host to network , short numberunsigned long htonl(unsigned long);//host to net , long number unsigned short ntohs(unsigned short);//net to host, short number…………网络地址初始化对于IP地址的示意,因为咱们大部分时候是以点分十进制表示法来了解的。然而计算机保留的是二进制序列,所以在初始化真正的IP地址时,咱们须要可能在点分十进制和二进制之间相互转换的API ...

October 27, 2021 · 6 min · jiezi

关于c++:c11新特性完美转发

什么是完满转发? 它指的是函数模板能够将本人的参数“完满”地转发给外部调用的其它函数。 完满,示意能保障被转发参数的左、右值属性不变。“不完满“函数举例: template<typename T>void function(T t) // 非援用,形参会对实参进行拷贝。{ // 对于函数外部来说,t有本人的名称,也能够获取它的存储地址,因而它永远都是左值。 otherdef(t);} 12345传递给 otherdef() 函数的参数 t 永远都是左值。C++11实现完满转发: 问题1:怎么解决函数模板参数的左、右值接管问题? C++11 规范中规定,通常状况下右值援用模式的参数只能接管右值,不能接管左值。 但对于函数模板中应用右值援用语法定义的参数来说,它不再恪守这一规定,既能够接管右值,也能够接管左值(此时的右值援用又被称为“万能援用”)。template<typename T>void function(T &&t) //既能够承受左值,又能够承受右值{ otherdef(t); // t持续传参,在otherdef()中又变成了左值} 12345记住:在实现完满转发时,只有函数模板的参数类型为 T&&,则 C++ 能够自行精确地断定出理论传入的实参是左值还是右值。问题2:如何将函数模板接管到的形参连同其左、右值属性,一起传递给被调用的函数? C++11引入了一个模板函数 forword() 。//实现完满转发的函数模板template <typename T>void function(T&& t) { otherdef(forward<T>(t)); //将函数模板接管到的形参连同其左、右值属性,一起传递给被调用的函数 } 1 2 3 4 5残缺代码示例: include <iostream>using namespace std;//重载被调用函数,查看完满转发的成果void otherdef(int & t) { cout << "lvalue\n";}void otherdef(const int & t) { cout << "rvalue\n";}//实现完满转发的函数模板template <typename T>void function(T&& t) { ...

October 25, 2021 · 1 min · jiezi

关于c++:C之父Bjarne-Stroustrup倾情献作现代C白皮书

这是 C++ 之父 Bjarne Stroustrup 的 HOPL4 论文的中文版。 HOPL 是 History of Programming Languages(编程语言历史)的缩写,是 ACM(Association of Computing Machines,国内计算机协会)旗下的一个会议,约每十五年举办一次。Bjarne 的这篇论文是他为 2021 年 HOPL IV 会议筹备的论文,也是他的第三篇 HOPL 论文。在这三篇前后距离近三十年的论文里,Bjarne 记录了 C++ 的残缺历史,从 1979 年到 2020 年。这篇 HOPL4 论文尤其重要,因为它涵盖了 C++98 之后的所有 C++ 版本,从 C++11 直到 C++20。如果你对更晚期的历史也感兴趣的话,则能够参考他的其余 HOPL 论文,及他在 1994 年出版的《C++ 语言的设计与演变》(The Design and Evolution of C++)。 鉴于这篇论文对于 C++ 从业者的重要性,寰球 C++ 及系统软件技术大会的主办方 Boolan 组织了一群译者,把这篇重要论文翻译成了中文,让 C++ 开发人员对 C++ 的设计准则和历史有一个零碎的理解。 加入论文翻译工作的译者有(按拼音序):陈常筠、高辉、何荣华、何一娜、侯晨、侯金亭、彭亚、王奎、王绍新、吴咏炜、徐宁、杨文波、于波、余水清、翟华明、章爱国、张云潮。 论文翻译的校对和体例对立工作由吴咏炜、杨文波、张云潮实现。最初的公布由吴咏炜实现。 欢送大家来评论区收费支付C++白皮书 2021寰球C++及系统软件技术大会11月25-26日上海万豪虹桥大酒店

October 22, 2021 · 1 min · jiezi

关于c++:封装构造和析构2

没有任何返回值。初始化列表, 效率更高,用不了this指针一是应用初始化列表,二是在构造函数体内进行赋值操作。应用初始化列表次要是基于性能问题,对于内置类型,如int, float等,应用初始化类表和在构造函数体内初始化差异不是很大,然而对于类类型来说,最好应用初始化列表,为什么呢?由下面的测试可知,应用初始化列表少了一次调用默认构造函数的过程,这对于数据密集型的类来说,是十分高效的。同样看下面的例子,咱们应用初始化列表来实现Test2的构造函数 struct Test2{ Test1 test1 ;Test2(Test1 &t1):test1(t1){}} 应用同样的调用代码,输入后果如下。 construct Test1copy constructor for Test1第一行输入对应 调用代码的第一行。第二行输入对应Test2的初始化列表,间接调用拷贝构造函数初始化test1,省去了调用默认构造函数的过程。所以一个好的准则是,能应用初始化列表的时候尽量应用初始化列表。举例 lass X {public: int m_i; X(int value = 0) :m_i(value) { printf("this = %p", this); cout << "X(int)构造函数被调用" << endl; } X(const X &tmpv) { printf("this = %p", this); cout << "X拷贝构造函数被调用" << endl; } X& operator=(const X &tmpv) { printf("this = %p", this); cout << "X拷贝赋值运算符被调用" << endl; return *this; } ~X() { printf("this = %p", this); cout << "X析构函数被调用" << endl; }};class Y{public: X xobj;//类类型对象 Y(int tmpvalue) :xobj(1000)//这里结构了xobj,此处若没有应用初始化成员列表,消耗了一次结构函数调用的机会 // 编译器角度(没用初始化列表) //X xobj; //xobj.X::X(); // 编译器角度(用了初始化列表) //X xobj; //xobj.X::X(1000); { //xobj = 1000;//若不应用初始化列表。这里结构一个长期对象,把长期对象内容给了xobj,之后开释xobj //编译器视角 //x tmpobj;// (1)生成长期对象 //tmpobj.X::X(1000);// (2)长期对象调用构造函数 //xobj.X::operator=(tmpobj);// (3)调用拷贝赋值运算符 //tmpobj.X::~X(); // (4)调用析构函数 }};

October 22, 2021 · 1 min · jiezi

关于c++:类和对象

类和类型**类型** 变量int a;long long b;char c;double d;float e;类 对象Cat cat; 栈空间,编译器保护Cat * ptr_cat = new cat(); 堆空间, 程序员本人保护内存区:代码区 常量区, 堆, 栈一个类在内存中须要占多大的内存空间呢:是由成员变量的动态属性决定的, 还有一个额定的因素占用内存空间: 虚办法(TODO)编译器主动创立一个八字节的虚函数表,是链表的构造1231123 内存对齐 内存对齐基本上是通明的,这是编译器该干的活,编译器为程序中的每个数据单元安顿在适合的地位上,从而导致了雷同的变量,不同申明程序的构造体大小的不同。缩小不必要的内存开销, int放在一起 double 放在一起 采纳#pragma pack(1) 解决序列化和反序列化带来的内存对齐问题//52个字节了,减少成员办法不影响类对象的内存大小(虚办法除外),为什么要这么设计呢?成员办法存在代码段的,class People{string name;int age;double height;double weight;};//56个字节 //加上一行后变成了52对齐class People{string name;int age;double height;double weight;int children;};//64个字节class People{string name;int age;int children;double height;double weight;void say(string word);};//56个字节编译后存在内存中say变成了 void say(People * this, string word);类封装class默认private, struct 默认public 私有继承(public)私有继承在C++中是最罕用的一种继承形式,咱们先来看一个示例: 1 #include<iostream> 2 using namespace std; 3 class Father{ 4 public: 5 Father()=default; 6 void Father_show1(){ 7 cout<<"调用Father类的public办法:Father_show1"<<endl; 8 } 9 protected:10 void Father_show2(){11 cout<<"调用Father类的protected办法:Father_show2"<<endl;12 }13 private:14 void Father_show3(){15 cout<<"调用Father类的private办法:Father_show3"<<endl;16 }17 }; 18 19 class Son:public Father{20 public:21 Son()=default;22 void Son_fun1(){23 cout<<"调用Son类的public办法:Son_fun1"<<endl;24 Father_show1();25 Father_show2();26 //Father_show3(); //谬误:无奈调用Father类的private办法 27 }28 protected:29 void Son_fun2(){30 cout<<"调用Son类的protected办法:Son_fun2"<<endl;31 Father_show1();32 Father_show2();33 //Father_show3(); //谬误:无奈调用Father类的private办法 34 }35 private:36 void Son_fun3(){37 cout<<"调用Son类的private办法:Son_fun3"<<endl;38 Father_show1();39 Father_show2();40 //Father_show3();//谬误:无奈调用Father类的private办法 41 }42 };43 44 int main(){45 Son s;46 s.Son_fun1(); //正确,只能调用对象的public办法47 s.Father_show1();48 //s.Son_fun2(); //谬误:不能调用对象的protected办法49 //s.Father_show2();50 //s.Son_fun3(); //谬误:不能调用对象的private办法51 //s.Father_show3();52 return 0;53 }对私有继承的了解:三种属性能力的强弱:public<protected<private在C++的继承中,子类会继承父类中除构造函数和析构函数之外的所有成员(正所谓儿子无奈继承父亲的生死) 。而私有继承(public)就相当于先将从父类那里继承的全副成员放到子类的public局部,如下: ...

October 20, 2021 · 4 min · jiezi

关于c++:More-Effective-C技术篇将constructor和nonmember-function虚化

所谓virtual constructor是某种函数,视其取得的输出,可产生不同类型的对象。有一种特地的virtual constructor——所谓virtual copy constructor——也被宽泛地使用、virtual copy constructor会返回一个指针,指向其调用者(某对象)的一个新正本。基于这种行为,virtual copy constructor通常以copyself或cloneself命令,或者间接命名为clone。当derived class从新定义其base class的一个虚函数时,不再须要肯定得申明与本来雷同的返回类型。如果函数的返回类型是个指针或援用,指向一个base class,那么derived class的函数能够返回一个指向该base class的derived class的指针或援用。这样就能够申明出像virtual copy constructor这样的函数。non-member function的虚化非常容易:写一个虚函数做理论工作,再写一个什么都不做的非虚函数,只负责调用虚函数。为了缩小函数调用老本,能够将非虚函数inline化。上面就是virtual copy constructor和virtual non-member function的例子。 #include <iostream>#include <list>class NLComponent{public: // 申明 virtual copy constructor virtual NLComponent *clone() const = 0; virtual std::ostream& print(std::ostream& s) const = 0; NLComponent() {} virtual ~NLComponent() {}};class TextBlock : public NLComponent{public: // virtual copy constructor TextBlock *clone() const override {return new TextBlock(*this);} std::ostream& print(std::ostream& s) const override { s << "I'm TextBlock" << std::endl; return s; }};class Graphic : public NLComponent{public: // virtual copy constructor Graphic *clone() const override {return new Graphic(*this);} std::ostream& print(std::ostream& s) const override { s << "I'm Graphic" << std::endl; return s; }};// 将 Non-Member Function的行为虚化inline std::ostream& operator<<(std::ostream& s, const NLComponent& c){ return c.print(s);}class NewsLetter{public: NewsLetter() {} ~NewsLetter() {} // copy constructor NewsLetter(const NewsLetter& rhs); void AddComponet(NLComponent* c); void PrintComponents();private: std::list<NLComponent*> components;};NewsLetter::NewsLetter(const NewsLetter& rhs){ for (auto it = rhs.components.begin(); it != rhs.components.end(); it++) { components.push_back((*it)->clone()); }}void NewsLetter::AddComponet(NLComponent* c){ components.push_back(c);}void NewsLetter::PrintComponents(){ for (auto it = components.begin(); it != components.end(); it++) { std::cout << *(*it); }}int main(){ TextBlock tb; Graphic gp; NewsLetter nl1; nl1.AddComponet(&tb); nl1.AddComponet(&gp); NewsLetter nl2(nl1); nl2.PrintComponents();}

October 17, 2021 · 1 min · jiezi

关于c++:sizeof与内存对齐总结

1.根本类型sizeof运算符返回类型或者数据对象的长度(字节), int a=1; float b=1.0; double c=1.0; long d=1; char e = '1'; cout<<sizeof(a)<<" "<<sizeof(b)<<" "<<sizeof(c)<<" "<<sizeof(d)<<" "<<sizeof(e)<<endl; cout<<sizeof(int)<<" "<<sizeof(float)<<" "<<sizeof(double)<<" "<<sizeof(long)<<" "<<sizeof(char)<<endl;输入: 4 4 8 8 14 4 8 8 12.动态数组将sizeof运算符用于动态数组名,失去的是整个数组的字节数,用于数组元素,则失去的是元素长度。 int arr[3]={1,1,1}; float arr1[3]={1.0,1.0,1.0}; double arr2[3]={1.0,1.0,1.0}; cout<<sizeof(arr)<<" "<<sizeof(arr1)<<" "<<sizeof(arr2)<<endl; cout<<sizeof(arr[0])<<" "<<sizeof(arr1[1])<<" "<<sizeof(arr2[2])<<endl;输入: 12 12 244 4 83.动静数组然而当sizeof运算符用于动静数组,就很神奇。 vector<int>arr1(1,0); vector<int>arr2(2,0); vector<int>arr3(3,0); cout<<sizeof(arr1)<<" "<<sizeof(arr2)<<" "<<sizeof(arr3)<<endl;输入: 24 24 24能够看到不论vector有多少元素,输出都是24,为啥? 这是因为 vector 是C++规范库中的容器类,其外部实现了三个指针, start;finish;end_of_storage;别离代表头, 尾(理论应用), vector 存储尾部(占用的,通常大于理论应用),finish-start对应于size(),end_of_storage-start对应于capacity(),如下图所示: ...

October 17, 2021 · 1 min · jiezi

关于c++:COMP9319-2018s2-Assignment-2-BWT

COMP9319 2018s2 Assignment 2: BWTThis assignment contains two tasks: BWT encode and backward search.RequirementsBWT encodeYour first task in this assignment is to create a special BWT encoder that will encode a file with delimiter-separated text values (similar to a CSV file) into two files: a BWT encoded file; and an auxiliary positional information file. Your BWT encoded file may carry some positional information (i.e., first record, second record, and so on; whilst the size of the BWT encoded file is the same as the original file, and the frequencies of each character in these two files are the same). The BWT encoded file must be the same size as the original text file, and the auxiliary must not be larger than the original text file. (Note that different students may have different, working schemes to capture this positional information). ...

October 16, 2021 · 11 min · jiezi

关于c++:Assignment-3-Description-jack编序器

Assignment 3 Description: Computer Systems (2000_7081 Combined) https://myuni.adelaide.edu.au... 1/7 Assignment 3 Descripon Assignment 3 - Jack Compiler Weighng and Due DatesMarks for this assignment contribute 20% of the overall course mark.Marks for functionality will be awarded automatically by the web submission system.Due dates: Milestone - 11:55pm Friday of week 11, Final - 11:55pm Monday of week 13.Late penalties: For each part, the maximum mark awarded will be reduced by 25% per day /part day late. If your mark is greater than the maximum, it will be reduced to the maximum.Core Body of Knowledge (CBOK) Areas: abstraction, design, hardware and software, dataand information, and programming.Project DescriponIn this assignment you will complete a variation of projects 10 and 11 in the nand2tetris course,reworked descriptions of Nand2Tetris Projects 10 and 11 are shown below. In particular, you willwrite the following programs that are used to implement different components of an optimisingJack compiler that compiles a Jack class into Hack Virtual Machine (VM) code:parser - this parses a Jack program and constructs an abstract syntax tree.codegen - this takes an abstract syntax tree and outputs equivalent VM code.pretty - this takes an abstract syntax tree and produces a carefully formatted Jack program.optimiser-r* - this copies an abstract syntax tree and removes redundant code wherepossible.lint^ - this takes an abstract syntax tree and annotates it with warning and / or errormessages.Notes:^Only for students enrolled in the undergraduate offering, COMP SCI 2000.*Only for students enrolled in the postgraduate offering, COMP SCI 7081.SVN RepositoryNote: this assignment assumes that you have already created directories for every assignment,workshop, project and exam in your svn repository, as described on the Startup Files forWorkshops and Assignments (https://myuni.adelaide.edu.au... for-workshops-and-assignments) page. ...

October 15, 2021 · 10 min · jiezi

关于c++:EEE102-软件工程

EEE102 Assessment 3 EEE102 C++ Programming and Software Engineering IIAssessment 3Assessment Number 3Contribution to Overall Marks 35%Submission Deadline Wednesday, 01-May-2019, 23:59How the work should be submitted?SOFT COPY ONLY !(MUST be submitted through ICE so that the TAs can run your programs during marking.)Make sure your name and ID are printed on the cover page of your report.Assessment OverviewThis assessment aims at testing some basic concepts of C++ programming and initiates the routine ofcode development using the software development process (SDP), namely the five main steps of thesoftware development process: ...

October 15, 2021 · 4 min · jiezi

关于c++:设计模式必备知识点六大设计原则

设计模式,即Design Patterns,是指在软件设计中,被重复应用的一种代码设计教训。 应用设计模式的目标是为了可重用代码,进步代码的可扩展性和可维护性。 设计模式这个术语是上个世纪90年代由Erich Gamma、Richard Helm、Raplh Johnson和Jonhn Vlissides四个人总结提炼进去的,并且写了一本 Design Patterns 的书。我的项目地址: https://gitee.com/baichen9187... 一,开闭准则开闭准则的定义开闭准则是最根底的设计准则,它领导咱们如何建设一个稳固,灵便的零碎。开闭准则定义如下: Software entities like classes,modules and functions should be openfor extension but closed for modifications.OOP实践中5个准则之一(别离是S O L I D,繁多职责准则、开闭准则、里氏替换、接口隔离、依赖反转) 一个软件实体如类,模块和函数应该对扩大凋谢,对批改敞开。 什么是开闭准则开闭准则明确的通知咱们:实体实现应该对扩大凋谢,对批改敞开,其含意是说一个实体应该通过扩大来实现变动,而不是通过批改已有的代码来实现变动的。那什么是实体呢?软件实体包含以下几个局部: 我的项目或软件产品中依照肯定的逻辑规定划分的模块形象和类办法 开闭准则的作用开闭准则是面向对象程序设计的终极目标,它使软件实体领有肯定的适应性和灵活性的同时具备稳定性和延续性。具体来说,其作用如下。 对软件测试的影响软件恪守开闭准则的话,软件测试时只须要对扩大的代码进行测试就能够了,因为原有的测试代码依然可能失常运行。能够进步代码的可复用性粒度越小,被复用的可能性就越大;在面向对象的程序设计中,依据原子和形象编程能够进步代码的可复用性。能够进步软件的可维护性恪守开闭准则的软件,其稳定性高和延续性强,从而易于扩大和保护。开闭准则的长处进步代码复用性进步可维护性进步灵活性易于测试#include <iostream>class Number {protected: double pi = 3.1415926;public: virtual double getCircularArea(int d) = 0; virtual double getRectangularArea(int a, int b) = 0;};class NumberArea : public Number {public: double getCircularArea(int r) { return ((double)r * r) * this->pi; } double getRectangularArea(int a, int b) { return (double)a * b; }};int main(){ NumberArea num; double cricular = num.getCircularArea(1); std::cout << cricular << std::endl; }二,繁多职责准则繁多职责定义繁多职责准则(SRP:Single responsibility principle)又称繁多性能准则,面向对象五个根本准则(SOLID)之一。它规定一个类应该只有一个发生变化的起因。该准则由罗伯特·C·马丁(Robert C. Martin)于《麻利软件开发:准则、模式与实际》一书中给出的。马丁示意此准则是基于汤姆·狄马克(Tom DeMarco)和Meilir Page-Jones的著述中的内聚性准则倒退出的。 ...

October 12, 2021 · 5 min · jiezi

关于c++:xmake-v258-发布新增-PascalSwig-程序和-Lua53-运行时支持

xmake 是一个基于 Lua 的轻量级跨平台构建工具,应用 xmake.lua 保护我的项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对老手十分敌对,短时间内就能疾速入门,可能让用户把更多的精力集中在理论的我的项目开发上。 这个版本,咱们次要减少了对 Pascal 语言我的项目和 Swig 模块的构建反对,而对于上个版本新增的 Vala 语言反对,咱们也做了进一步改良,减少了对动静库和动态库的构建反对。 除此之外,xmake 当初也曾经反对了可选的 Lua5.3 运行时,提供更好的跨平台反对能力,目前 xmake 曾经可能在 LoongArch 架构上失常运行。 我的项目源码官网文档入门课程新个性介绍Pascal 语言反对目前,咱们能够应用跨平台的 Free pascal 工具链 fpc 去编译构建 Pascal 程序,例如: 控制台程序add_rules("mode.debug", "mode.release")target("test") set_kind("binary") add_files("src/*.pas")动静库程序add_rules("mode.debug", "mode.release")target("foo") set_kind("shared") add_files("src/foo.pas")target("test") set_kind("binary") add_deps("foo") add_files("src/main.pas")咱们也能够通过 add_fcflags() 接口增加 Pascal 代码相干的编译选项。 更多例子见:Pascal examples Vala 库编译反对上个版本,咱们新增了对 Vala 语言的反对,然而之前只能反对控制台程序的编译,无奈生成库文件。而这个版本中,咱们额定减少了对动态库和动静库的编译反对。 动态库程序咱们可能通过 add_values("vala.header", "mymath.h") 设置导出的接口头文件名,通过 add_values("vala.vapi", "mymath-1.0.vapi") 设置导出的 vapi 文件名。 add_rules("mode.release", "mode.debug")add_requires("glib")target("mymath") set_kind("static") add_rules("vala") add_files("src/mymath.vala") add_values("vala.header", "mymath.h") add_values("vala.vapi", "mymath-1.0.vapi") add_packages("glib")target("test") set_kind("binary") add_deps("mymath") add_rules("vala") add_files("src/main.vala") add_packages("glib")动静库程序add_rules("mode.release", "mode.debug")add_requires("glib")target("mymath") set_kind("shared") add_rules("vala") add_files("src/mymath.vala") add_values("vala.header", "mymath.h") add_values("vala.vapi", "mymath-1.0.vapi") add_packages("glib")target("test") set_kind("binary") add_deps("mymath") add_rules("vala") add_files("src/main.vala") add_packages("glib")更多例子见:Vala examples ...

October 12, 2021 · 4 min · jiezi

关于c++:C基础总结

C++语法根底(数据类型、运算符、程序流程构造、数组、函数、指针、构造体)1 C++初识1.1规范代码格局#include<iostream>using namespace std;int main() { cout << "Hello world" << endl; system("pause"); return 0;}1.2 正文作用:在代码中加一些阐明和解释,不便本人或其余程序员程序员浏览代码 两种格局 单行正文:// 形容信息 通常放在一行代码的上方,或者一条语句的开端,==对该行代码阐明==多行正文: /* 形容信息 */ 通常放在一段代码的上方,==对该段代码做整体阐明==提醒:编译器在编译代码时,会疏忽正文的内容1.3 变量作用:给一段指定的内存空间起名,不便操作这段内存 语法:数据类型 变量名 = 初始值; //变量的定义//语法:数据类型 变量名 = 初始值int a = 10;留神:C++在创立变量时,必须给变量一个初始值,否则会报错1.4 常量作用:用于记录程序中不可更改的数据 C++定义常量两种形式 \#define 宏常量: #define 常量名 常量值 ==通常在文件上方定义==,示意一个常量永远不可批改const润饰的变量 const 数据类型 常量名 = 常量值 ==通常在变量定义前加关键字const==,润饰该变量为常量,不可批改能够通过指针援用批改//1、宏常量 永远不可批改#define day 7int main() { //2、const润饰变量 能够通过指针援用批改 const int month = 12; system("pause"); return 0;}1.5 关键字作用:关键字是C++中事后保留的单词(标识符) 在定义变量或者常量名字的时候,不要用关键字C++关键字如下: asmdoifreturntypedefautodoubleinlineshorttypeidbooldynamic_castintsignedtypenamebreakelselongsizeofunioncaseenummutablestaticunsignedcatchexplicitnamespacestatic_castusingcharexportnewstructvirtualclassexternoperatorswitchvoidconstfalseprivatetemplatevolatileconst_castfloatprotectedthiswchar_tcontinueforpublicthrowwhiledefaultfriendregistertrue deletegotoreinterpret_casttry 提醒:在给变量或者常量起名称时候,不要用C++得关键字,否则会产生歧义。 ...

October 10, 2021 · 4 min · jiezi

关于c++:C-gRPC-Quick-Start

简介gRPC是一种由Google推出的RPC框架,开源,跨语言,跨平台,高性能。 gRPC次要是基于protobuf设计实现的。 本文次要介绍如何在C++中应用gRPC。 装置不像Java,配置一个maven插件,增加相应的maven依赖,就能够搭建好gRPC环境。 C++个别须要下载gRPC的源码,而后编译构建,失去须要的库文件,protoc编译器,以及gRPC插件。 下载源码git clone --recurse-submodules -b v1.41.0 https://github.com/grpc/grpccd grpc创立cmake构建目录mkdir -p cmake/buildcd cmake/build生成makefilecmake -DgRPC_INSTALL=ON \ -DgRPC_BUILD_TESTS=OFF \ -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \ ../..MY_INSTALL_DIR变量指定了最终生成的库文件,protoc的装置地位,linux零碎个别为/usr/local 构建make -j装置make install此命令会依据第三部指定的MY_INSTALL_DIR的,将构建进去的库装置到相应的地位。比方protoc就放在${MY_INSTALL_DIR}/bin目录下, 头文件就放在${MY_INSTALL_DIR}/include/grpc目录下。 当然,执行上述命令须要装置g++, cmake, git等工具。 HelloWorld应用gRPC首先须要写proto文件,形容rpc,供客户端和服务端应用。 proto文件接口定义hello.proto // protobuf版本syntax = "proto3";// rpc申请的定义message HelloRequest { optional string name = 1;}// rpc响应的定义message HelloReply { optional string message = 1;}// rpc服务的定义,两个函数service HelloWorld { rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}}服务端proto仅定义了接口,还须要在服务端写程序,实现rpc。server.cc #include "hello.grpc.pb.h"#include <string>#include <grpcpp/grpcpp.h>// rpc服务实现class HelloServiceImpl : public HelloWorld::Service{ grpc::Status SayHello(grpc::ServerContext* context, const HelloRequest* req, HelloReply* rsp) { std::cout << "Request SayHello From " << context->peer() << std::endl; rsp->set_message("hello " + req->name() + "!"); return grpc::Status::OK; } grpc::Status SayHelloAgain(grpc::ServerContext* context, const HelloRequest* req, HelloReply* rsp) { std::cout << "Request SayHelloAgain From " << context->peer() << std::endl; rsp->set_message("hello " + req->name() + " again!!"); return grpc::Status::OK; }};// 启动运行int main(int argc, char** argv){ std::string address("localhost:5000"); HelloServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort(address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); std::cout << "Server Listening on port: " << address << std::endl; server->Wait(); return 0;}客户端客户端调用服务端的,client.cc ...

October 8, 2021 · 2 min · jiezi

关于c++:CISC235-Data-Structures

CISC-235 Data StructuresAssignment 2February 5, 20191 ProblemsIn this assignment, you will implement a binary search tree structure and associatedfunctions. The goal of this assignment is to: get familiar with the implementation of a binary (search) tree.use stacks (you need to implement the stack ADT as well).get familiar with iterative/recursive operations on a binary (search) tree.1.1 Implementation of Stack Using Array-based List: 10pointsCreate a class named Stack using array-based list provided by a particularprogramming language (e.g., List in Python). Your class should contain aninitialization function, as well as the following functions (we just mention thename of each function, you need determine what is the input): isEmpty, this function checks whether the current Stack instance is empty.It should return true if the Stack is empty. push, this function should takes a data item as input and add it into theStack. pop, this function should return the data item on the top of the currentStack and remove it from the Stack. top, this function should return the data item on the top of the currentStack without modifying the Stack. size, this function should return the number of data items in the Stack.11.2 Implementation a Binary Search Tree: 80 pointsBinary search tree (BST) is a special type of binary tree which satisfies thebinary search property, i.e., the key in each node must be greater than any keystored in the left sub-tree, and less than any key stored in the right sub-tree.See a sample binary search tree below:Figure 1: Binary Search Tree 1Your task is to create a class named BinarySearchTree satisfying the followingrequirements (you can create more instance variables if you want):1) Each node inside the BST has at least these attributes: value(data storedin the node), leftChild (reference to another node), and rightChild (referenceto another node)2) Must have an insert function (i.e., insert a new node). You may assumethat the values to be stored in the tree are integers.3) Must have a searchPath function that returns a list of all the values visitedon the search path. For example, on a particular tree T, T.searchPath(10)might return 8, 20, 15, 14, 10.4) Must have a getTotalDepth function that computes the sum of thedepths of all nodes in the tree. Your getTotalDepth function should runin O(n) time. Hint: if a node knows its own depth, it can tell its childrenwhat their depth is. Each node can add its own depth to the total depthreported by its children, and return that sum. The value returned by theroot will be the total depth of the tree.5) Mush have a getWeightBalanceFactor function. The weight balancefactor of a binary tree is a measure of how well-balanced it is, i.e., howevenly its nodes are distributed between the left and right subtrees ofeach node. More specifically, weight balance factor of a binary tree is themaximum value of the absolute value of (number of nodes in left subtreenumberof nodes in right subtree) for all nodes in the tree. For example,given the binary search tree shown in Figure 2, your function should returnalthough if you just look at the root node, the difference in the numberof nodes in the left subtree and right subtree is 1.2Figure 2: Binary Search Tree 21.3 Reconstruct a Binary Search Tree From a File Usinga Stack: 30 pointsCreate a loadTreeFromFile function in the above BinarySearchTree class.This function takes a String filename as input, and return a BinarySearchTreeobject. The file list the nodes of the tree in post-order sequence, one node perline. Each line contains a string which is the data value stored in the node, andtwo other 0/1 tags. The first tag indicates whether or not this node has a leftchild, the second tag indicates whether the node has a right child. For example,to reconstruct the sample binary search tree in Figure 1, the input file containsthe following lines:0 00 01 10 00 11 1The above information is sufficient to uniquely determine any binary tree.The tree can be reconstructed from the file using the following algorithm:create empty stack of BinarySearchTreewhile there is another line of input in the file:read a line (containing data and 2 tags)if the second tag is 1, pop an element from the stack and call itright_treeif the first tag is 1, pop an element from the stack and call itleft_treecrate a new binary search tree with data as its root and left_treeand right_tree as its subtrees (if they exist)push the new tree onto your stackWhen you exit the while loop, the stack should contains one element and that3is the tree you want to return. Note that you should check the second tag(indicating if the node has right child or not) first. And if your right tree andleft tree is empty, you should create a new tree with only one node, i.e., theroot node. You should use the Stack you created in Section 1.1.1.4 Test Code and Style: 30 pointsYou must comment your code, and write test code. In your test code, youshould:1) Reconstruct a binary search tree T (should be the one shown in Figure 1)by reading a file containing the lines shown in Section 1.3.2) Calculate the total depth of T.3) Calculate the Weight Balance Factor of T.4) Insert a new value, i.e., 5, into T.5) Print path of searching the value 5.6) Calculate the total depth of T.7) Calculate the Weight Balance Factor of T.Assignment RequirementsThis assignment is to be completed individually (we have the right to run anyclone detection tool). You need submit your documented source code (Stackclass + BinarySearchTree class + test code). If you have multiple files, pleasecombine all of them into a .zip archive and submit it to OnQ system. The .ziparchive should contain your student number. Deadline: Feb-18 12:00am, 2019.WX:codehelp

October 3, 2021 · 5 min · jiezi

关于c++:Leetcode-637-最长递增子序列的个数

LIS回顾本题是LIS的进阶版本,上周课上老师举了LIS做例子,在解答本题前,先将LIS的代码贴在这里 class Solution {public: int lengthOfLIS(vector<int>& nums) { auto n = (int)nums.size(); vector<int> dp(n, 1); for (int i = 0; i < n; ++i) { for (int j = 0; j < i; ++j) { if (nums[j] < nums[i]) { dp[i] = max(dp[i], dp[j] + 1); } } } return *max_element(dp.begin(), dp.end()); }};LIS最长回升子序列是一道经典的动静布局问题,解DP问题的关键在于定义正确的状态(有最优子结构)并找到正确的状态转移方程,在LIS中,状态转移方程为 $$LIS_j=max(LIS_i)+1,where\ 0\le i<j,\&\& \ nums[i] < nums[j] $$ 最长递增子序列的个数上面思考第637题,求最长递增子序列的个数要求最长递增子序列的个数,首先要晓得最长子序列的长度,在LIS的代码中,DP数组代表的就是以第i个数结尾的最长子序列的长度。那么遍历一遍DP数组,咱们就能够晓得最长子序列结尾的那个数有多少种抉择,也就是 vector<int> dp;int cnt = 0;int maxlen = *max_element(dp.begin(), dp.end());for(auto d:dp){ if(d == maxlen) cnt ++;}那么,如果咱们曾经晓得最初一位,那么倒数第二位的取值又有多少种状况呢?这启发我能够应用DFS广度优先搜寻,穷举最长LIS所有可能的状况,代码如下 ...

September 29, 2021 · 2 min · jiezi

关于c++:深度解密epoll-如何工作的

epoll 是Linux平台下的一种特有的多路复用IO实现形式,与传统的 select 相比,epoll 在性能上有很大的晋升。本文次要解说 epoll 的实现原理,而对于 epoll 的应用能够参考相干的书籍或文章。相干视频举荐面试中正经“八股文”网络原理tcp/udp,网络编程epoll/reactor6种epoll的设计,让你吊打面试官,而且他不能还嘴epoll原理分析以及三握四挥的解决LinuxC++后盾服务器开发架构师收费学习地址 epoll 的创立要应用 epoll 首先须要调用 epoll_create() 函数创立一个 epoll 的句柄,epoll_create() 函数定义如下:int epoll_create(int size);参数 size 是因为历史起因遗留下来的,当初不起作用。当用户调用 epoll_create() 函数时,会进入到内核空间,并且调用 sys_epoll_create() 内核函数来创立 epoll 句柄,sys_epoll_create() 函数代码如下: asmlinkage long sys_epoll_create(int size){ int error, fd = -1; struct eventpoll *ep; error = -EINVAL; if (size <= 0 || (error = ep_alloc(&ep)) < 0) { fd = error; goto error_return; } fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep); if (fd < 0) ep_free(ep);error_return: return fd;}sys_epoll_create() 次要做两件事件:调用 ep_alloc() 函数创立并初始化一个 eventpoll 对象。调用 anon_inode_getfd() 函数把 eventpoll 对象映射到一个文件句柄,并返回这个文件句柄。咱们先来看看 eventpoll 这个对象,eventpoll 对象用于治理 epoll 监听的文件列表,其定义如下: ...

September 22, 2021 · 4 min · jiezi

关于c++:现代计算机数字表示

古代计算机数字示意1 概述古代计算机存储和解决信息以二值信号示意。二值信号能够很容易的被示意、存储和传输,例如能够示意为导线上的高电压、低电压。对二值信号进行存储和执行计算的电子电路非常简单牢靠,制造商能够在一个独自的硅片上集成数百万甚至数十亿个这样的电路。 对于数字而言,有三种比拟重要的示意: 无符号(unsigned)编码:对大于等于零的整数进行编码补码(two's-complement)编码:对有符号的整数进行编码,蕴含正负数浮点数(floating-point)编码:对实数进行编码表示,应用以2为基准的迷信记数法形式计算机的示意是应用无限数量的位来对一个数字进行编码,因而,当数字太大以至于不能示意时,运算后果就会溢出(overflow)。 值得注意的是,整数的编码和浮点数的编码解决数字示意有限性的形式不一样: 浮点数编码能够对一个较大范畴的值域进行编码,然而这种示意只是近似的,存在精度缺失整数编码尽管只能编码一个范畴较小的值域,然而是准确的示意,无效范畴内不会存在精度缺失问题。2 信息存储信息在计算机的内存中,往往都是以二进制补码模式存在。对于如何在内存中不便的应用信息,须要两个规定: 信息的地址是什么?如何对信息的字节进行排列?对于被存储为间断字节的信息对象,对象的地址为所应用字节中最小的地址。 2.1 字节程序排列一个信息的字节有两个通用的规定: 大端法(big endian):信息的高无效字节寄存在高地址,地无效字节寄存在地址小端法(litter endian):信息的地无效字节寄存在高地址,高无效字节寄存在低地址例如,存在一个整型变量int x = n,它的十六进制示意为0x12345678。那么内存会给它调配四个字节的存储空间。假如地址值为0x100-0x103。那么就0x100就是低地址,0x103就是高地址。 对于字节的最高无效字节和最低无效字节的程序,是从左往右顺次升高的。12为最高无效字节,顺次类推,78就是最低无效字节。 对于大多数Intel兼容机,都是采纳小端模式;IBM和Oracle大多数机器则是大端模式;对于挪动端来说,无论是Andriod还是IOS都是小端模式。 2.2 字符与字符串的示意2.2.1 字符示意C或者C++中,对字符采纳某种规范编码进行示意,比拟罕用的有ASCII字符码,就是应用1个字节的bit位来对字符进行编码。 遗憾的是ASCII编码仅仅实用于英文文档,对于一些特殊字符以及中文编码不反对。所以Unicode联合会整顿订正了反对宽泛语言编码的根本编码-Unicode对立字符集,应用32位来示意字符。 2.2.2 字符串的示意在C或者C++中,字符串被编码为一个以NULL('\0',值为0)结尾的字符数组。每个字符由规范编码表示。 2.3 整数示意整数用bit位来示意也有两种不同的形式。一种是只能示意非负整数;另外一种是可能示意负整数、零以及正整数。无论哪种形式,在内存中都是以补码模式存在。 2.3.1 无符号整数编码无符号数总是大于等于零,所以无符号数的补码就是它二进制原码自身: unsigned int num = 10;// 原码 int类型占用32bit0000 0000 0000 0000 0000 0000 0000 1010// 补码 内存中寄存的是补码0000 0000 0000 0000 0000 0000 0000 1010无符号整数的所有bit位都是数字无效位。 2.3.2 有符号整数编码对于有符号的整数,将其转换为二进制之后,最高位(最右边)bit位代表符号位,不参加数据表示。其中0示意负数,1示意正数。 对于补码: 负数补码 = 负数二进制原码正数补码 = 正数二进制原码除了符号位,其余位取反 + 1//无符号整数 负数int a = 3;// 3的原码。第一位是符号位,3是负数,所以是00000 0000 0000 0000 0000 0000 0000 0011// 3的补码0000 0000 0000 0000 0000 0000 0000 0011 //无符号整数 符数int a = -3;// -3的原码 第一位符号位,3是正数 所以是11000 0000 0000 0000 0000 0000 0000 0011// 而后是反码,除了符号位,其余位取反1111 1111 1111 1111 1111 1111 1111 1100// 最初是补码:反码 + 1,这就是负3在内存中的模式1111 1111 1111 1111 1111 1111 1111 11012.4 实数示意在计算机中,实数示意办法与整数的示意办法是不同的。 ...

September 18, 2021 · 1 min · jiezi

关于c++:Linux多核系统的负载均衡

后面的调度学习都是默认在单个 CPU 上的调度策略。咱们晓得为了 CPU 之间缩小“烦扰”,每个 CPU 上都有一个工作队列。运行的过程种可能会呈现有的 CPU 很忙,有的 CPU 很闲,如下图所示:为了防止这个问题的呈现,Linux 内核实现了 CPU 可运行过程队列之间的负载平衡。因为负载平衡是在多个核上的平衡,所以在解说负载平衡之前,咱们先看下多核的架构。将 task 从负载较重的 CPU 上转移到负载绝对较轻的 CPU 上执行,这个过程就是负载平衡的过程。多核架构这里以 Arm64 的 NUMA(Non Uniform Memory Access) 架构为例,看下多核架构的组成。从图中能够看出,这是非一致性内存拜访。每个 CPU 拜访 local memory,速度更快,提早更小。因为 Interconnect 模块的存在,整体的内存会形成一个内存池,所以 CPU 也能拜访 remote memory,然而绝对 local memory 来说速度更慢,提早更大。咱们晓得一个多外围的 SOC 片上零碎,内部结构是很简单的。内核采纳 CPU 拓扑构造来形容一个 SOC 的架构,应用调度域和调度组来形容 CPU 之间的档次关系。LinuxC++后盾服务器开发架构师收费学习地址【文章福利】:小编整顿了一些集体感觉比拟好的学习书籍、视频材料共享在群文件外面,有须要的能够自行添加哦!~点击退出(须要自取) CPU 拓扑每一个 CPU 都会保护这么一个构造体实例,用来形容 CPU 拓扑。 struct cpu_topology { int thread_id; int core_id; int cluster_id; cpumask_t thread_sibling; cpumask_t core_sibling;};thread_id: 从 mpidr_el1 寄存器中获取core_id:从 mpidr_el1 寄存器中获取cluster_id:从mpidr_el1寄存器中获取thread_sibling:以后 CPU 的兄弟 thread。core_sibling:以后 CPU 的兄弟Core,即在同一个 Cluster 中的 CPU。能够通过 /sys/devices/system/cpu/cpuX/topology 查看 cpu topology 的信息。cpu_topology 构造体是通过函数 parse_dt_topology() 解析 DTS 中的信息建设的:kernel_init() -> kernel_init_freeable() -> smp_prepare_cpus() -> init_cpu_topology() -> parse_dt_topology()static int __init parse_dt_topology(void){ struct device_node *cn, *map; int ret = 0; int cpu; cn = of_find_node_by_path("/cpus"); ------(1) if (!cn) { pr_err("No CPU information found in DT\n"); return 0; } /* * When topology is provided cpu-map is essentially a root * cluster with restricted subnodes. */ map = of_get_child_by_name(cn, "cpu-map"); ------(2) if (!map) goto out; ret = parse_cluster(map, 0); ------(3) if (ret != 0) goto out_map; topology_normalize_cpu_scale(); /* * Check that all cores are in the topology; the SMP code will * only mark cores described in the DT as possible. */ for_each_possible_cpu(cpu) if (cpu_topology[cpu].cluster_id == -1) ret = -EINVAL;out_map: of_node_put(map);out: of_node_put(cn); return ret;}找到 dts 中 cpu topology 的根节点 "/cpus"找到 "cpu-map" 节点解析 "cpu-map" 中的 cluster以 i.mx8qm 为例,topology 为:”4A53 + 2A72”,dts中定义如下: ...

September 17, 2021 · 6 min · jiezi

关于c++:test笔记

语句语句根底常见类别表达式语句:表达式后加分号 表达式求值,后抛弃 可能产生副作用 2 + 3; //表达式; int x; x = 3; //表达式求值,返回值x后抛弃 //副作用:x值的扭转空语句:仅蕴含一个分号的语句 罕用在循环体 复合语句(语句体):{ ......} 结尾无分号 { int x = 3; x+=1; std::cout << x << "\n";} //一条复合语句 //造成独立的域(语句域) //域中可定义长期变量,准确管制生命周期 { ...};//两条语句 ;为空语句int x = 2;{ int x = 3; x++;}程序语句与非程序语句程序语句 语义上依照先后顺序执行理论的执行程序可能产生变动,编译器优化/硬件乱序执行等与硬件流水线紧密结合,执行效率较高非程序语句 在执行过程中引入跳转,产生简单变动**分支预测**晋升性能,预测谬误可能导致执行性能升高会限度编译器优化goto 通过标签指定跳转地位限度: 不能跨函数跳转 向前(下)跳转时,不能越过初始化语句向后跳转可能导致对象的销毁与从新初始化goto实质对应汇编中的跳转指令 不足结构性的含意 容易造成逻辑凌乱 防止应用int main(){ int x = 1; if(x) goto label; x++;label: return 0'}分支语句非程序语句分为分支语句与循环语句 if 与 switch ...

September 17, 2021 · 6 min · jiezi

关于c++:彻底学会使用epoll二ET的读写操作实例分析

相干视频举荐面试中正经“八股文”网络原理tcp/udp,网络编程epoll/reactorepoll 原理分析 以及 reactor 模型利用epoll原理分析以及三握四挥的解决LinuxC++后盾服务器开发架构师收费学习地址彻底学会应用epoll(一)——ET模式实现剖析接上一篇首先,看程序四的例子。l 程序四 #include <unistd.h>#include <iostream>#include <sys/epoll.h>using namespace std;int main(void){ int epfd,nfds; struct epoll_event ev,events[5];//ev用于注册事件,数组用于返回要解决的事件 epfd=epoll_create(1);//只须要监听一个描述符——规范输入 ev.data.fd=STDOUT_FILENO; ev.events=EPOLLOUT|EPOLLET;//监听读状态同时设置ET模式 epoll_ctl(epfd,EPOLL_CTL_ADD,STDOUT_FILENO,&ev);//注册epoll事件 for(;;) { nfds=epoll_wait(epfd,events,5,-1); for(int i=0;i<nfds;i++) { if(events[i].data.fd==STDOUT_FILENO) cout<<"hello world!"<<endl; } }};这个程序的性能是只有规范输入写就绪,就输入“hello world!”。运行后果: 咱们发现这将是一个死循环。上面具体分析一下这个程序的执行过程:(1) 首先初始buffer为空,buffer中有空间可写,这时无论是ET还是LT都会将对应的epitem退出rdlist(对应第一节图中的红线),导致epoll_wait就返回写就绪。(2) 程序想规范输入输入”hello world!”和换行符,因为规范输入为控制台的时候缓冲是“行缓冲”,所以换行符导致buffer中的内容清空,这就对应第二节中ET模式下写就绪的第二种状况——当有旧数据被发送走时,即buffer中待写的内容变少得时候会触发fd状态的扭转。所以下次epoll_wait会返回写就绪。之后反复这个过程始终循环上来。咱们再看程序五。程序五绝对程序四这里仅仅去掉了输入的换行操作。即: cout<<"hello world!";运行后果如下: 咱们看到程序成挂起状态。因为第一次epoll_wait返回写就绪后,程序向规范输入的buffer中写入“hello world!”,然而因为没有输入换行,所以buffer中的内容始终存在,下次epoll_wait的时候,尽管有写空间然而ET模式下不再返回写就绪。回顾第一节对于ET的实现,这种状况起因就是第一次buffer为空,导致epitem退出rdlist,返回一次就绪后移除此epitem,之后尽管buffer依然可写,然而因为对应epitem曾经不再rdlist中,就不会对其就绪fd的events的在检测了。程序六int main(void){ int epfd,nfds;struct epoll_event ev,events[5];//ev用于注册事件,数组用于返回要解决的事件epfd=epoll_create(1);//只须要监听一个描述符——规范输入ev.data.fd=STDOUT_FILENO;ev.events=EPOLLOUT;//应用默认LT模式epoll_ctl(epfd,EPOLL_CTL_ADD,STDOUT_FILENO,&ev);//注册epoll事件for(;;){ nfds=epoll_wait(epfd,events,5,-1); for(int i=0;i<nfds;i++){ if(events[i].data.fd==STDOUT_FILENO) cout<<"hello world!";}}}; 程序六绝对程序五仅仅是批改ET模式为默认的LT模式,咱们发现程序再次死循环。这时候起因曾经很分明了,因为当向buffer写入”hello world!”后,尽管buffer没有输入清空,然而LT模式下只有buffer有写空间就返回写就绪,所以会始终输入”hello world!”,当buffer满的时候,buffer会主动刷清输入,同样会造成epoll_wait返回写就绪。程序七int main(void) { int epfd,nfds;struct epoll_event ev,events[5];//ev用于注册事件,数组用于返回要解决的事件epfd=epoll_create(1);//只须要监听一个描述符——规范输入ev.data.fd=STDOUT_FILENO;ev.events=EPOLLOUT|EPOLLET;//监听读状态同时设置ET模式epoll_ctl(epfd,EPOLL_CTL_ADD,STDOUT_FILENO,&ev);//注册epoll事件for(;;){ nfds=epoll_wait(epfd,events,5,-1); for(int i=0;i<nfds;i++){ if(events[i].data.fd==STDOUT_FILENO) cout<<"hello world!"; ev.data.fd=STDOUT_FILENO; ev.events=EPOLLOUT|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,STDOUT_FILENO,&ev); //从新MOD事件(ADD有效)} ...

September 15, 2021 · 4 min · jiezi

关于c++:谈-C17-里的-Visitor-模式

Visitor Pattern访问者模式是一种行为模式,容许任意的拆散的访问者可能在管理者管制下拜访所治理的元素。访问者不能扭转对象的定义(但这并不是强制性的,你能够约定为容许扭转)。对管理者而言,它不关怀到底有多少访问者,它只关怀一个确定的元素拜访程序(例如对于二叉树来说,你能够提供中序、前序等多种拜访程序)。 组成Visitor 模式蕴含两个次要的对象:Visitable 对象和 Vistor 对象。此外,作为将被操作的对象,在 Visitor 模式中也蕴含 Visited 对象。 一个 Visitable 对象,即管理者,可能蕴含一系列形态各异的元素(Visited),它们可能在 Visitable 中具备简单的构造关系(但也能够是某种单纯的包容关系,如一个简略的 vector)。Visitable 个别会是一个简单的容器,负责解释这些关系,并以一种规范的逻辑遍历这些元素。当 Visitable 对这些元素进行遍历时,它会将每个元素提供给 Visitor 令其可能拜访该 Visited 元素。 这样一种编程模式就是 Visitor Pattern。 接口为了可能察看每个元素,因而实际上必然会有一个束缚:所有的可被察看的元素具备独特的基类 Visited。 所有的 Visitors 必须派生于 Visitor 能力提供给 Visitable.accept(visitor&) 接口。 namespace hicc::util { struct base_visitor { virtual ~base_visitor() {} }; struct base_visitable { virtual ~base_visitable() {} }; template<typename Visited, typename ReturnType = void> class visitor : public base_visitor { public: using return_t = ReturnType; using visited_t = std::unique_ptr<Visited>; virtual return_t visit(visited_t const &visited) = 0; }; template<typename Visited, typename ReturnType = void> class visitable : public base_visitable { public: virtual ~visitable() {} using return_t = ReturnType; using visitor_t = visitor<Visited, return_t>; virtual return_t accept(visitor_t &guest) = 0; };} // namespace hicc::util场景以一个实例来说,假如咱们正在设计一套矢量图编辑器,在画布(Canvas)中,能够有很多图层(Layer),每一图层蕴含肯定的属性(例如填充色,透明度),并且能够有多种图元(Element)。图元能够是 Point,Line,Rect,Arc 等等。 ...

September 14, 2021 · 4 min · jiezi

关于c++:CC和C的关系以把大象放进冰箱里举例

最近得用unity做虚构仿真相干的货色,当然,它的出名还是在游戏界,像王者光荣就是应用 unity 开发的。 应用unity就要学习C#语言,我始终认为C#是C++的降级版本,因为C++是C的改进版,然而C#与前两者的关系就相当于Java和JavaScript,没半毛钱关系。 C语言C语言是一门面向过程的计算机编程语言,与C++、C#、Java等面向对象编程语言有所不同。 C语言的设计指标是提供一种能以繁难的形式编译、解决低级存储器、仅产生大量的机器码以及不须要任何运行环境反对便能运行的编程语言。 并且它是一门非常优良而又重要的语言,Window,Liunx,UXIX零碎都是应用C语言编写的,可见他的重要水平。 C++C++ 是一种动态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,反对过程化编程、面向对象编程和泛型编程。 它被认为是一种中级语言,综合了高级语言和低级语言的特点。 OOP(面向对象)语言特点: 封装性:一个手机是由很多部件形成的,有处理器,存储器,输入输出设置,屏幕,电池等,把这些货色组装在一起就是手机了,这就是封装性。继承性:老子生了儿子,儿子继承了老子的个性,就有了继承性。多态性:我在家是父母的儿子,在公司是老板的员工,在深圳就是深圳人,在面向对象的语言中,调用雷同的办法会有不同的行为,这就是多态。C Sharp又叫C#,是一个古代的、通用的、面向对象的编程语言,它是由微软(Microsoft)开发的,由Ecma 和ISO 核准认可的。 至于它的命名,咱们来看看起源: 微软为了解救Visual Basic未实现的事业剽窃jxx语言并起名为 j++被吃官司后,学聪慧了,谎称本人是C语言的改良命名为C#对,剽窃的就是Java语言,当初的C# 和 Java有着惊人的类似。 三者的关系经典案例:把大象放到冰箱里 C:C语言是一个极其高冷的人,因而答复都是冷冷的: 我:你好C语言,我想把大象放到冰箱里,帮我做好不好? C:好 我:那咱们要怎么做呢? C:猜 我:额。。。是不是应该先发明一只大象? C:是 我:怎么发明呢? C:猜 我只好去翻了一下文档,哦,malloc一块内存啊。 我:好的,我用malloc,申请一块空间放大象好不好? C:好 我:额。。。大象怎么结构呢? C:猜 我。。。去看了看大象的构造 我:好吧。。。我定义了一个大象的数据结构,接下来怎么做? C:猜 我心里一阵说不出的感觉。。。 我:哦好吧,我发明一个冰箱,步骤应该和大象差不多。 C:嗯 我翻看了冰箱的构造,而后定义了一个冰箱的struct。 我:好了,冰箱结构进去了,怎么放呢? C:哼 我。。。默默在Stack Overflow上输出如何把大象放进冰箱 C。 我:终于找到答案了,定义一个办法,把大象的鼻子放进去、眼睛放进去、耳朵放进去。OK,都放进去了。C,你输入一下看看吧。 C:烫烫烫烫烫烫烫 我:哈哈哈哈C你终于不高冷了 。。。 我:哎,你咋不谈话了?C?你发烧了吗? 立即一盆水倒上去。 完结。 C++:C++是一个常识渊博的孩子,绝对年老,也没那么高冷。 我:C艹,咱们把大象放冰箱好吗? C++:滚 谈话的不高冷呢? 我:额我错了,敬爱的C++,咱们把大象放冰箱好吧。 C++:好的么么哒,大象的数据类型曾经有人定义好了,冰箱也有人定义好了,你须要别离结构一个哦。 我:好的。 于是我翻看了文档后晓得了用new来结构 我:OK,敬爱的C++,我想结构一个大象。 C++:好的,结构大象的办法有13个,请问你抉择哪一种呢? 我。。。 我:你介绍一下吧。 C++:OK,首先能够在栈下面结构,这么做的益处呢是能够不便资源管理,而且语法也难看一些,能够利用RAII,如果你不晓得什么事RAII,你能够去cppreference下面查一下,当然你也能够在堆上结构,能够结构一只很大很大的大象,还有。。。。。。。 ...

September 12, 2021 · 1 min · jiezi

关于c++:pollepoll实现分析二epoll实现

相干视频举荐面试中正经“八股文”网络原理tcp/udp,网络编程epoll/reactorepoll 原理分析 以及 reactor 模型利用epoll原理分析以及三握四挥的解决LinuxC++后盾服务器开发架构师收费学习地址 通过上一剖析,poll运行效率的两个瓶颈曾经找出,当初的问题是怎么改良。首先,如果要监听1000个fd,每次poll都要把1000个fd 拷入内核,太不迷信了,内核干嘛不本人保留曾经拷入的fd呢?答对了,epoll就是本人保留拷入的fd,它的API就曾经阐明了这一点——不是 epoll_wait的时候才传入fd,而是通过epoll_ctl把所有fd传入内核再一起"wait",这就省掉了不必要的反复拷贝。其次,在 epoll_wait时,也不是把current轮流的退出fd对应的设施期待队列,而是在设施期待队列醒来时调用一个回调函数(当然,这就须要“唤醒回调”机制),把产生事件的fd纳入一个链表,而后返回这个链表上的fd。另外,epoll机制实现了本人特有的文件系统eventpoll filesystem 1. 内核数据结构(1) struct eventpoll { spinlock_t lock; struct mutex mtx; wait_queue_head_t wq; /* Wait queue used by sys_epoll_wait() ,调用epoll_wait()时, 咱们就是"睡"在了这个期待队列上*/ wait_queue_head_t poll_wait; /* Wait queue used by file->poll() , 这个用于epollfd本事被poll的时候*/ struct list_head rdllist; /* List of ready file descriptors, 所有曾经ready的epitem都在这个链表外面*/ structrb_root rbr; /* RB tree root used to store monitored fd structs, 所有要监听的epitem都在这里*/ epitem *ovflist; /*寄存的epitem都是咱们在传递数据给用户空间时监听到了事件*/. struct user_struct *user; /*这里保留了一些用户变量,比方fd监听数量的最大值等*/ }; 通过epoll_ctl接口退出该epoll描述符监听的套接字则属于socket filesystem,这点肯定要留神。每个增加的待监听(这里监听和listen调用不同)都对应于一个epitem构造体,该构造体已红黑树的构造组织,eventpoll构造中保留了树的根节点(rbr成员)。同时有监听事件到来的套接字的该构造以双向链表组织起来,链表头保留在eventpoll中(rdllist成员)。 ...

September 11, 2021 · 5 min · jiezi

关于c++:pollepoll实现分析一poll实现

相干视频举荐面试中正经“八股文”网络原理tcp/udp,网络编程epoll/reactorepoll 原理分析 以及 reactor 模型利用epoll原理分析以及三握四挥的解决LinuxC++后盾服务器开发架构师收费学习地址1.期待队列在Linux内核中期待队列有很多用处,可用于中断解决、进程同步及定时。咱们在这里只说,过程常常必须期待某些事件的产生。期待队列实现了在事件上的条件期待: 心愿期待特定事件的过程把本人放进适合的期待队列,并放弃管制全。因而,期待队列示意一组睡眠的过程,当某一条件为真时,由内核唤醒它们。期待队列由循环链表实现,由期待队列头(wait_queue_head_t)和期待队列项(wait_queue)组成,其元素(期待队列项)蕴含指向过程描述符的指针。每个期待队列都有一个期待队列头(wait queue head),期待队列头是一个类型为wait_queue_head_t的数据结构定义期待队列头(相干内容能够在linux/include/wait.h中找到)期待队列头构造体的定义: struct wait_queue_head { spinlock_t lock; //自旋锁变量,用于在对期待队列头 struct list_head task_list; // 指向期待队列的list_head}; typedef struct __wait_queue_head wait_queue_head_t;应用期待队列时首先须要定义一个wait_queue_head,这能够通过DECLARE_WAIT_QUEUE_HEAD宏来实现,这是动态定义的办法。该宏会定义一个wait_queue_head,并且初始化构造中的锁以及期待队列。 Linux中期待队列的实现思维如下图所示,当一个工作须要在某个wait_queue_head上睡眠时,将本人的过程管制块信息封装到wait_queue中,而后挂载到wait_queue的链表中,执行调度睡眠。当某些事件产生后,另一个工作(过程)会唤醒wait_queue_head上的某个或者所有工作,唤醒工作也就是将期待队列中的工作设置为可调度的状态,并且从队列中删除。 (2)期待队列中寄存的是在执行设施操作时不能取得资源而挂起的过程定义期待对列: struct wait_queue { unsigned int flags; //prepare_to_wait()里有对flags的操作,查看以得出其含意 #define WQ_FLAG_EXCLUSIVE 0x01 //一个常数,在prepare_to_wait()用于批改flags的值 void * private //通常指向当前任务管制块 wait_queue_func_t func; //唤醒阻塞工作的函数 ,决定了唤醒的形式 struct list_head task_list; // 阻塞工作链表};typedef struct __wait_queue wait_queue_t;【文章福利】:小编整顿了一些集体感觉比拟好的学习书籍、视频材料共享在群文件外面,有须要的能够自行添加哦!(须要自取) 1.select/poll毛病 select/poll的毛病在于: 1.每次调用时要反复地从用户态读入参数。 2.每次调用时要反复地扫描文件描述符。 3.每次在调用开始时,要把以后过程放入各个文件描述符的期待队列。在调用完结后,又把过程从各个期待队列中删除。内核实现2.1 次要数据结构:(1) struct poll_table_entry { struct file filp; wait_queue_t wait;//外部有一个指针指向一个过程 wait_queue_head_t wait_address;//期待队列头部(期待队列有多个wait_queue_t组成,通过双链表连贯)};(2) struct poll_table_page { ...

September 10, 2021 · 2 min · jiezi

关于c++:Linux-epoll-与-C-协程

简介 本文应用 C++20 引入的协程来编写一个 Linux epoll 程序。在此实现中,用户应用异步操作时再也无需提供本人的回调函数。以此处实现的 asyncRead() 为例: 应用 asyncRead() 所需的参数和 read() 大致相同,无需传入回调;asyncRead() 的外部会向 epoll 注册要监听的文件描述符、感兴趣的事件和要执行的回调(由实现提供,而无需使用者传入);当事件未就绪时,co_await asyncRead() 会挂起以后协程;当事件就绪时,epoll 循环中会执行具体的 I/O 操作(此处将其提交到 I/O 线程池中执行),当 I/O 操作实现时,复原协程的运行。1. ThreadPool此处应用了两个线程池: I/O 线程池:用于执行 I/O 操作;工作线程池:用于解决客户端连贯(此处以 tcp 回显程序为例)。此处应用的是本人实现的线程池,具体实现见 https://segmentfault.com/a/11...。 2. IOContextIOContext 类对 Linux epoll 做了简略的封装。 io_context.h: #ifndef IOCONTEXT_H#define IOCONTEXT_H#include <sys/epoll.h>#include <unistd.h>#include <unordered_map>#include <functional>#include "thread_pool.h"using callback_t = std::function<void()>;struct Args{ callback_t m_cb;};class IOContext{public: IOContext(int nIOThreads=2, int nJobThreads=2); // 监听文件描述符 fd,感兴趣事件为 events,args 中蕴含要执行的回调 bool post(int fd, int events, const Args& args); // 提交工作至工作线程池 bool post(const Task& task); // 不再关注文件描述符 fd,并移除相应的回调 void remove(int fd); // 继续监听、期待事件就绪 void run();private: int m_fd; std::unordered_map<int, Args> m_args; std::mutex m_lock; ThreadPool m_ioPool; // I/O 线程池 ThreadPool m_jobPool; // 工作线程池};#endifio_context.cpp: ...

September 7, 2021 · 4 min · jiezi

关于c++:谈-C17-里的-FlyWeight-模式

回顾享元模式,思考实作它的各种问题。 Prologue略过 FlyWeight Pattern实践享元模式,是将简单对象的雷同的组成元素抽出并独自保护的一种结构型设计模式。这些雷同的组成元素被称为共享元件,它们在一个独自的容器中被唯一性地治理,而简单对象只需持有到该惟一实例的参考,而无需反复创立这样的雷同的元素,从而可能大幅度地削减内存占用。 以字处理器为例,每个字符都具备独立的、区别于其它字符的非凡属性:例如字体款式,背景、边框、对齐等等。如果一个文档中全副字符都独自存储一份它的所有属性的正本,那么这将会是宏大的内存需要。但思考到一大堆(例如1000个)字符可能都有雷同的“宋体,9pt”这样的属性,那么实际上咱们只须要独自存储一份“宋体,9pt”的字体款式属性,而一个字符只须要一个指向该字体款式属性的指针就能够了,这就比1000个字符的1000个字体款式属性拷贝要节约的多。 相似的案例还有相当多,例如例子零碎中的每个粒子(例如子弹、弹片,或者敌方飞机)都有一些雷同的属性(例如色彩,轮廓等等)占地不小,但值却雷同。 工厂模式很容易想到,咱们能够在一个工厂中就地治理享元对象。当客户以具体值来申请一个享元对象时,工厂会从一个字典中检索享元是否存在,而后返回该元素的参考援用给客户。如果享元尚未存在,那么工厂会创立它,而后在返回援用。 不可变性依照传统的说法,享元模式要求这些雷同的局部(享元,雷同的组成元素)是不可变的。但这并不是铁律。 一个办法是,以一个享元为整体,咱们能够整体批改对象持有的享元参考。 例如咱们正在批改字处理器中的一个单词的字体款式,从“宋体,9pt”改为“黑体,12pt”,那么咱们能够间接批改援用指向。也就是说,咱们提供 character.apply_font_style(font_style& style) 这样的整体批改接口。 另一个办法能够从更细的粒度登程进行批改,例如从“宋体,9pt”改为“宋体,10pt”,但在产生变更时,尝试从工厂中查证新值的参考。也就是说,咱们提供 character.set_font_size(float pt) 这样的接口,但在其实现过程中记得去查证享元工厂(管理器)以求更新外部援用。 C++ 实现传统的享元模式的实现形式有这样的示例代码: namespace hicc::dp::flyweight::basic { /** * flyweight Design Pattern * * Intent: Lets you fit more objects into the available amount of RAM by sharing * common parts of state between multiple objects, instead of keeping all of the * data in each object. */ struct shared_state { std::string brand_; std::string model_; std::string color_; shared_state(const std::string &brand, const std::string &model, const std::string &color) : brand_(brand) , model_(model) , color_(color) { } friend std::ostream &operator<<(std::ostream &os, const shared_state &ss) { return os << "[ " << ss.brand_ << " , " << ss.model_ << " , " << ss.color_ << " ]"; } }; struct unique_state { std::string owner_; std::string plates_; unique_state(const std::string &owner, const std::string &plates) : owner_(owner) , plates_(plates) { } friend std::ostream &operator<<(std::ostream &os, const unique_state &us) { return os << "[ " << us.owner_ << " , " << us.plates_ << " ]"; } }; /** * The flyweight stores a common portion of the state (also called intrinsic * state) that belongs to multiple real business entities. The flyweight accepts * the rest of the state (extrinsic state, unique for each entity) via its * method parameters. */ class flyweight { private: shared_state *shared_state_; public: flyweight(const shared_state *o) : shared_state_(new struct shared_state(*o)) { } flyweight(const flyweight &o) : shared_state_(new struct shared_state(*o.shared_state_)) { } ~flyweight() { delete shared_state_; } shared_state *state() const { return shared_state_; } void Operation(const unique_state &unique_state) const { std::cout << "flyweight: Displaying shared (" << *shared_state_ << ") and unique (" << unique_state << ") state.\n"; } }; /** * The flyweight Factory creates and manages the flyweight objects. It ensures * that flyweights are shared correctly. When the client requests a flyweight, * the factory either returns an existing instance or creates a new one, if it * doesn't exist yet. */ class flyweight_factory { std::unordered_map<std::string, flyweight> flyweights_; std::string key(const shared_state &ss) const { return ss.brand_ + "_" + ss.model_ + "_" + ss.color_; } public: flyweight_factory(std::initializer_list<shared_state> lists) { for (const shared_state &ss : lists) { this->flyweights_.insert(std::make_pair<std::string, flyweight>(this->key(ss), flyweight(&ss))); } } /** * Returns an existing flyweight with a given state or creates a new one. */ flyweight get(const shared_state &shared_state) { std::string key = this->key(shared_state); if (this->flyweights_.find(key) == this->flyweights_.end()) { std::cout << "flyweight_factory: Can't find a flyweight, creating new one.\n"; this->flyweights_.insert(std::make_pair(key, flyweight(&shared_state))); } else { std::cout << "flyweight_factory: Reusing existing flyweight.\n"; } return this->flyweights_.at(key); } void list() const { size_t count = this->flyweights_.size(); std::cout << "\nflyweight_factory: I have " << count << " flyweights:\n"; for (std::pair<std::string, flyweight> pair : this->flyweights_) { std::cout << pair.first << "\n"; } } }; // ... void AddCarToPoliceDatabase( flyweight_factory &ff, const std::string &plates, const std::string &owner, const std::string &brand, const std::string &model, const std::string &color) { std::cout << "\nClient: Adding a car to database.\n"; const flyweight &flyweight = ff.get({brand, model, color}); // The client code either stores or calculates extrinsic state and passes it // to the flyweight's methods. flyweight.Operation({owner, plates}); }} // namespace hicc::dp::flyweight::basicvoid test_flyweight_basic() { using namespace hicc::dp::flyweight::basic; flyweight_factory *factory = new flyweight_factory({ {"Chevrolet", "Camaro2018", "pink"}, {"Mercedes Benz", "C300", "black"}, {"Mercedes Benz", "C500", "red"}, {"BMW", "M5", "red"}, {"BMW", "X6", "white"} }); factory->list(); AddCarToPoliceDatabase(*factory, "CL234IR", "James Doe", "BMW", "M5", "red"); AddCarToPoliceDatabase(*factory, "CL234IR", "James Doe", "BMW", "X1", "red"); factory->list(); delete factory;}其输入后果如同这样: ...

September 7, 2021 · 6 min · jiezi

关于c++:C正则表达式

1. 匹配根底用法: #include <iostream>#include <string>#include <regex>int main(){ using namespace std::regex_constants; std::string filename("Foo.txt"); std::regex pattern("[a-z]+\\.txt", ECMAScript|icase); // icase: 疏忽大小写 // filename 是否匹配 pattern bool matched = std::regex_match(filename, pattern); std::cout << std::boolalpha << matched; // true}提取子匹配(分组): std::string filename("foo.txt");std::regex pattern("([a-z]+)\\.([a-z]+)");std::smatch groups;// 如果 filename 匹配 pattern,则将匹配后果存入 groups 中bool matched = std::regex_match(filename, groups, pattern);if (matched){ for (size_t i = 0; i < groups.size(); i++) { /* groups[0] 是整个匹配的内容; groups[1] 是第一匹配分组的内容,以此类推。 */ std::ssub_match group = groups[i]; std::cout << "groups[" << i << "]: " << group.str() << '\n'; }}groups[0]: foo.txtgroups[1]: foogroups[2]: txt2. 搜寻根底用法: ...

September 6, 2021 · 2 min · jiezi

关于c++:谈-C17-里的-Builder-模式

曾经写了一篇 谈 C++17 里的 Factory 模式 ,起初又顺便肝了一篇 谈 C++17 里的 Singleton 模式 。看来是得要整一大堆了,对于懒惰的人来说这很麻烦。我不晓得是不是要打算会写残缺个 GoF 的集体了解以及新的的实现,缓缓看吧,做了就做了。回顾下构建者模式,并应答做类库时遇到的构建者模板类应如何实作的问题。 Prologue实际上,就我集体而言,真正地使用 builder pattern,反而是在 Java 开发经验中。流式接口也是如此。 Builder 模式就是为了分步骤结构一个对象用的,看图: FROM: HERE尽管很多时候咱们都只关怀 new 了对象后怎么操作它,然而有的时候有的场景里的确咱们只会关怀怎么 new 这个对象。这时候就是 Builder 了。 Builder Pattern实践Builder 模式是 Creational Patterns 中的一种。在 谈 C++17 里的 Factory 模式 中,咱们曾经介绍过创立型模式了,所以本文不再赘述了。 构建者模式的用意,就在于让你能够分步骤地构建简单对象,它容许你应用雷同(类似)的创立diamanté生产出不同类型和模式的对象。 对于 Builder 模式来说,一个重要的标记,只管这并不是规定但却往往约定俗成,就是以一个 .build() 调用作为完结。例如: auto shape = Builder() .choose(Shape.Rect) // choose a factory .setColor(COLOR.RED) .setBorderWidth(1) .setFill(COLOR.GRAY) .build();canva.place(shape, Position.Default);Builder 模式并非必须得要采纳流式接口。 反而在很多时候咱们须要和交互对象协商一个抉择,并将这个决定设置到 Builder 结构者中。直到全副协商实现之后,才应用 builder.build() 构建出最终产品实例。 ...

September 5, 2021 · 6 min · jiezi

关于c++:leetcodeJZ50第一个只出现一次的字符

题面 原题链接 代码本题有很多做法 动静布局(本人想进去的,工夫性能要比哈希表优良很多): int变量dpIndex,记录整个字符串中第一次只呈现一次的字符下标 int数组present[123],因为'z'的ascii码是122,初始化为全0 dp[i] = 前i个字符串中第一个只呈现一次的字符 动静布局过程 if s[i]!=dp[i-1] dp[i] = dp[i-1] else present[s[dpIndex]] = 1 dpIndex++ until present[s[dpIndex]] != 1 dp[dpIndex] = s[dpIndex] j = dpIndex源代码 class Solution {public: char firstUniqChar(string s) { char result = 'n'; int present[123]; for(int i=0; i<123;i++){ present[i] = 0; } int len = s.size(); if(len==0){ return ' '; } char dp[len]; for(char k:dp){ k=' '; } int dpIndex = 0; dp[0] = s[0]; int j= 1; for(j = 1;j<len;j++){ if(s[j] != dp[j-1]){ dp[j] = dp[j-1]; } else{ present[s[j]] = 1; while(dpIndex<len && present[s[dpIndex]] == 1){ dpIndex++; } if(dpIndex>=len){ return ' '; } dp[dpIndex] = s[dpIndex]; j = dpIndex; // if(j==len-1){ // return ' '; // } cout<<dpIndex<<endl; } } return dp[len-1]; }}; ...

September 4, 2021 · 1 min · jiezi

关于c++:C容器unorderedmap

1. 简介#include <unordered_map>template < class Key, // unordered_map::key_type class T, // unordered_map::mapped_type class Hash = std::hash<Key>, // unordered_map::hasher class Pred = std::equal_to<Key>, // unordered_map::key_equal class Alloc = std::allocator<std::pair<const Key, T>> // unordered_map::allocator_type> class unordered_map;unordered_map 具备如下性质: 唯一性:键是惟一的;无序性:键值对是无序存储的,元素被存储在桶中,如果两个元素领有雷同哈希值的键,则它们会被存储于同一桶中;具备常数工夫复杂度(均匀来说)的搜寻、插入、删除操作。2. 自定义键类型如果键是自定义类型,则须要提供相应的哈希函数,来计算键的哈希值。 办法1:显式提供相应的模板参数 #include <iostream>#include <unordered_map>#include <string>struct Key{ std::string first; std::string second;};struct KeyHash{ std::size_t operator()(const Key& k) const { return std::hash<std::string>()(k.first) ^ (std::hash<std::string>()(k.second) << 1); }};struct KeyEqual{ bool operator()(const Key& lhs, const Key& rhs) const { return lhs.first == rhs.first && lhs.second == rhs.second; }};int main(){ Key k1{ "John", "Doe" }, k2{ "Mary", "Sue" }; std::unordered_map<Key, std::string, KeyHash, KeyEqual> m = { { k1, "example"}, { k2, "another"} }; std::cout << m[k1] << '\n'; // example}办法2:显式特化 std::hash<> 模板 ...

September 4, 2021 · 3 min · jiezi

关于c++:C线程同步

C++ 规范库提供了如下线程同步机制: 互斥量(反对超时加锁、递归加锁)读写锁(共享互斥量,也反对超时加锁)互斥量包装器(基于 RAII 的思维)条件变量信号量(二元信号量、计数信号量)栅栏(反对重用)调用一次1. 互斥量#include <mutex>mutex:提供根底的互斥性能。 std::mutex mtx;mtx.lock(); // locks the mutex, blocks if the mutex is not availablebool ok = mtx.try_lock(); // tries to lock the mutex, returns if the mutex is not available mtx.unlock(); // unlocks the mutex timed_mutex:在 mutex 的根底上减少了超时加锁的性能。 #include <chrono>using namespace std::chrono_literals;std::timed_mutex mtx;// 以绝对工夫的模式指定超时工夫if (mtx.try_lock_for(100ms)){ // 已加锁}// 以相对工夫的模式指定超时工夫auto now = std::chrono::steady_clock::now();if (mtx.try_lock_until(now + 10s)){ // 已加锁}recursive_mutex:在 mutex 的根底上减少了递归加锁的性能(此时,lock() 函数能够被同一线程在不开释锁的状况下屡次调用)。 std::recursive_mutex mtx;void fun1() { mtx.lock(); // ... mtx.unlock();}void fun2() { mtx.lock(); // ... fun1(); // recursive lock becomes useful here mtx.unlock();};recursive_timed_mutex:在 timed_mutex 的根底上减少了递归加锁的性能。2. 读写锁#include <shared_mutex>shared_mutex ...

September 3, 2021 · 3 min · jiezi

关于c++:谈-C17-里的-Singleton-模式

Singleton Pattern回顾下单件模式,并思考实现一个通用的单件模板类以达成业务端低代码的指标。 Prologue设计模式中最平民的 Pattern 是哪一个?简直不会有任何一致,那必须是单件模式了。所谓单件模式,是在 C 语言开发历史上经验了各种各样的全局变量失控的折磨后倒退起来的一种技术,得益于 C++ 的封装能力,咱们能够将各种各样的全局变量管控在一个全局动态类(或者说一个类中全都是动态变量的实现形式)中,从而避免任意搁置全局变量带来的灾难性的结果。 我不用在此反复这些结果能有多糟,因为本文不是入门教材,而是实作教训的一个梳理而已。 很显著,动态类只不过是开始,它不是特地好的解决伎俩,因为除了可能集中在一处这一长处之外,这些动态变量还是是予取予求的,此外,晚期(C++11以前)的编译器没有明确和对立的动态变量初始化程序约定,所以你较难解决这些变量的初始化机会,再一个问题是,没有任何伎俩可能让你实现这些变量的懒加载(lazyinit),除非你将它们通通变成指针,那样的话,还会搞出多少事来只有天知道了。 实践根底Singleton 模式是 Creational Patterns 中的一种。在 谈 C++17 里的 Factory 模式 中,咱们曾经介绍过创立型模式了,所以本文不再赘述了。 单件模式的用意,及其根本实现,都是非常简单的,因此也不用消耗笔墨凑字数,间接略过。 Goal咱们想要的是一个可能 lazyinit 或者可能管制起初始化机会的、线程平安的单件模式。 所以上面会介绍 C++11(包含 C++0x)以来的若干可能理论使用的 Singleton 实现计划,但略过了更晚期的实现手法,以及略过了那些顾头不顾尾的示例性实现。嗯,其中一个是这样的: class singleton { static singleton* _ptr; singleton() {} public: singleton* get() { if (_ptr == NULL) _ptr = new singleton(); return _ptr; }};这个实现最为亲民,因为任何人无需任何常识(还是须要会c++的)也能一次性手写胜利,甚至不用放心手误或者其它什么编译谬误。它的弱点,较为显著的就先不提了,有时候会被展现者有意无意疏忽或者覆盖的一个重要弱点是,_ptr 是不会被 delete 的:但使用者会压服本人说我的程序就这么一个指针透露,这个代价是付得起的。 可怕吗?或者也不。这就是真的。 考究一点的家伙,晓得 C 提供了一种 atexit 的伎俩,所以会设法挂载一个退出时的 delete 例程,但还是不能解决在 if(_ptr==null) 这里可能产生的跨线程 data racing 问题。问题在于,一个 C++er 你搞个 C 技法在外面,那它也很不纯净的不是? ...

September 3, 2021 · 4 min · jiezi

关于c++:Crange

C++20 引入了 range 来简化对元素序列的解决(能够省略掉许多的循环遍历)。 1. range 和 viewrange range concept 通过提供一个迭代器以及一个哨兵来示意一个元素范畴,以容许对某个类型进行遍历。 template<class T>concept range = requires(T& t) { ranges::begin(t); ranges::end (t);};如,vector 就是一个 range: std::vector<int> vec{ 1, 2, 3 };auto it1 = std::ranges::begin(vec);auto it2 = std::ranges::end(vec);view view 是一个 range,且具备常数工夫复杂度的的拷贝、挪动和赋值操作(如,间接操作一对迭代器、或应用生成器来按需生成元素)。 template<class T>concept view = ranges::range<T> && std::movable<T> && ranges::enable_view<T>;template<class T>inline constexpr bool enable_view = std::derived_from<T, view_base> || /*is-derived-from-view-interface*/<T>;如,可通过 iota 来创立一个 view,相似于 Python 中的 range: auto v1 = std::views::iota(1); // [1, +inf)auto v2 = std::views::iota(1, 10); // [1, 10)for (int i : v2){ std::cout << i << ' ';}2. 范畴工厂会创立一个 view。 ...

September 2, 2021 · 3 min · jiezi

关于c++:C-的枚举类型

Prologue: C++ 中的枚举类型利用以及转换到字符串的加强:AWESOME_MAKE_ENUM,... Original From: HERE因为长期发现须要一个枚举量到字符串的转换器,所以罗唆梳理了一遍古往今来的枚举类型的变动。 于是奇怪的冷常识又减少了。 枚举类型 enum在 cxx11 之前,C/C++ 通过 enum 关键字申明枚举量。 // 匿名全局枚举量enum { DOG, CAT = 100, HORSE = 1000};enum Animal { DOG, CAT = 100, HORSE = 1000};从 cxx11 起,enum 容许应用不同于 integer 的其它数据类型。此时它的语法是这样的: enum 名字(可选) : 类型 { 枚举项 = 常量表达式 , 枚举项 = 常量表达式 , ... }enum 名字 : 类型 ;所以在必要时能够: enum smallenum: std::int16_t { a, b, c};但类型并不容许大过 int,受制于 CPU 字长。所以类型的反对简直没有任何实用价值,不晓得那堆人怎么想的,看来嵌入式真的很火。 enum class从 cxx11 起,咱们被举荐放弃 enum 改用有作用域的 enum class,也或者 enum struct。这时候申明枚举类型的形式如下: ...

September 2, 2021 · 4 min · jiezi

关于c++:FFmpeg-播放-RTSPWebcam-流

本文将介绍 FFmpeg 如何播放 RTSP/Webcam/File 流。流程如下: RTSP/Webcam/File > FFmpeg open and decode to BGR/YUV > OpenCV/OpenGL display代码: https://github.com/ikuokuo/rt..., 子模块 rtsp-local-playerFFmpeg 筹备git clone https://github.com/ikuokuo/rtsp-wasm-player.gitcd rtsp-wasm-playerexport MY_ROOT=`pwd`# ffmpeg: https://ffmpeg.org/git clone --depth 1 -b n4.4 https://git.ffmpeg.org/ffmpeg.git $MY_ROOT/3rdparty/source/ffmpegcd $MY_ROOT/3rdparty/source/ffmpeg./configure --prefix=$MY_ROOT/3rdparty/ffmpeg-4.4 \--enable-gpl --enable-version3 \--disable-programs --disable-doc --disable-everything \--enable-decoder=h264 --enable-parser=h264 \--enable-decoder=hevc --enable-parser=hevc \--enable-hwaccel=h264_nvdec --enable-hwaccel=hevc_nvdec \--enable-demuxer=rtsp \--enable-demuxer=rawvideo --enable-decoder=rawvideo --enable-indev=v4l2 \--enable-protocol=filemake -j`nproc`make installln -s ffmpeg-4.4 $MY_ROOT/3rdparty/ffmpeg./configure 手动抉择了:解码 h264,hevc 、解封装 rtsp,rawvideo 、及协定 file ,以反对 RTSP/Webcam/File 流。 其中, Webcam 因于 Linux ,故用的 v4l2。 Windows 可用 dshow, macOS 可用 avfoundation ,详见 Capture/Webcam。 ...

August 30, 2021 · 3 min · jiezi

关于c++:stdoptional-T-作为返回值时的优化问题及其他相关

旧文章,遗记了发到 segmentfault: 原文本文记录一次排查工作,顺便提供对于 C++ RVO 的一句话总结。 根本问题问题引发在我的 message-queue 开发过程中,有这么样的代码: inline std::optional<T> pop_front() { lock l(_m); _cv.wait(l, [this] { return _abort || !_data.empty(); }); if (_abort) return {}; // std::nullopt; auto r = std::move(_data.back()); _data.pop_back(); return r;}它的用意足够简略,就是从 std::deque _data 中弹出一个队尾元素。只是因为队列可能为空,所以有一个阻塞式的条件变量来期待队列中有有效值(前三行)。 依照直觉,我牵强附会地写完了这段代码。 随即我编写了一个测试片段: void test_mq() { hicc::pool::threaded_message_queue<hicc::debug::X> xmq; hicc::debug::X x1("aa"); { xmq.emplace_back(std::move(x1)); hicc_debug(" xmq.emplace_back(std::move(x1)) DONE. AND, xmq.pop_front() ..."); std::optional<hicc::debug::X> vv = xmq.pop_front(); hicc_debug("vv (%p): '%s'", (void *) &vv, vv.value().c_str()); } hicc_debug("x1 (%p): '%s'", (void *) &x1, x1.c_str());}hicc::debug::X 是一个专门用来调试 RVO,In-place construction,Copy Elision 等等个性的工具类,它平平无奇,只不过是在若干地位埋点冰打印 stdout 文字而已,这能够让咱们直观察看到哪些行为实际上产生了。 ...

August 29, 2021 · 3 min · jiezi

关于c++:C-复制消除问题

旧文章,遗记了发在segmentfault:原文谬误示范push_back 这么写是错的: template<class T> class threaded_message_queue { public: using lock = std::unique_lock<std::mutex>; void push_back(T t) { { lock l(_m); _data.push_back(std::move(t)); } _cv.notify_one(); } }};//入参 T t 导致了调用者在这里会产生一次长期对象 TMP 的复制,稍后在函数退出点处 TMP 还会被隐式析构。所以这个写法不是良构。 至于函数体中的 std::move(t) 也就是聊胜于无了,它并不会让 t 少掉 TMP 的复制,仅仅只是少掉了 t 到 _data 的一次复制而已。 正确工作做模板类开发时,常常会遇到 push_back 的这种场景。 正确的 push_back 应该蕴含左值复制和右值挪动两种语义,一般来说像是这样子: template<class T> class threaded_message_queue { public: using lock = std::unique_lock<std::mutex>; void emplace_back(T &&t) { { lock l(_m); _data.template emplace_back(std::move(t)); } _cv.notify_one(); } void push_back(T const &t) { { lock l(_m); _data.push_back(t); } _cv.notify_one(); } }};留神右值加上挪动语义才是一对搭配。T t 和挪动语义在一起只是一种错觉。 ...

August 29, 2021 · 2 min · jiezi

关于c++:谈-C17-里的-Factory-模式

本文不适宜初学者,你应该曾经对 Factory 模式有所理解,你对于 C++17 的常见个性也不生疏。Factory Pattern回顾下工厂模式,并思考实现一个通用的工厂模板类以达成业务端低代码的指标。 FROM: Refactoring Guru实践Factory 模式是 Creational Patterns 中的一种。 创立型模式所谓的创立型模式,次要蕴含这几种: Abstract factory 形象工厂模式。一组具备同一主题的对象创立工厂被独自封装起来,而多组不同的对象工厂具备对立形象的创立接口,该形象的创立接口即为形象工厂。Builder 构建者模式。目标是为了结构出一个简单对象,有必要将其蕴含的各种属性分门别类地顺次设定,以便令结构过程易于治理。个别采纳链式调用形式,而在属性结构结束之后,一个发令枪(例如 build())将指挥该简单对象被最终结构为实例。Factory method 古典的工厂模式。工厂办法模式。个别有一个动态的 create() 以便创建对象的实例。Prototype 原型模式。通过复制一个已有类型的形式创立新实例,即 clone()Singleton 单例模式。全局只有一个对象实例。以上为 GoF 的经典划分。不过,简直三十年过来了,当初还有更多的创立型模式: 和 Builder 略有不同的 生成器模式(generator pattern)提早初始化模式。Kotlin 中的 lazyinit 关键字是它的一种语言性反对。对象池模式。如果对象的创立相当耗时或者耗资源,那么一次性提前创立一组对象,须要时取用,用完后放回池子里。等等。工厂模式本文中提到工厂模式时,泛指 Factory Method,Factory,Abstract Factory 等等。综合起来看,工厂模式是指借助于一个厂房 Factory 来创立产品 Product 的某种编程范式。其目标是为了让消费者(业务端代码)不去关怀产品怎么制作进去的(简略地通过 Factory.create() 就可能失去),只需间接关怀怎么应用产品就行了。 从另一角度看,工厂模式具备这样的个性:我晓得工厂可能造清污产品,然而肥皂还是香皂就无所谓了,我想有点香味的,工厂就将会造香皂给我,我没有要求的,工厂造给我的可能就是肥皂了。也就是说,接口是那个样子,但工厂将会造出来的肯定合乎这个接口约定,但到底是那个类的实例就不肯定了(通常会由创立参数来决定)。 在编程实际上,工厂模式总是随同着一个产品根类,这是一个接口类,通常蕴含一系列形象办法作为业务端操作接口。对于简单的产品族来说则在该接口类的根底上会持续派生若干品类。 Factory Method最古典的工厂模式是 Factory Method,由 GoF 首次阐述的一种 Pattern。 以 Point 为例, namespace hicc::dp::factory::inner { class Transport { public: virtual ~Transport() {} virtual void deliver() = 0; }; class Trunk : public Transport { float x, y; public: explicit Trunk(double x_, double y_) { x = (float) x_, y = (float) y_; } explicit Trunk(float x_, float y_) { x = x_, y = y_; } ~Trunk() = default; void deliver() override { printf("Trunk::deliver()\n"); } friend std::ostream &operator<<(std::ostream &os, const Trunk &o) { return os << "x: " << o.x << " y: " << o.y; } static std::unique_ptr<Trunk> create(float x_, float y_) { return std::make_unique<Trunk>(x_, y_); } }; class Ship : public Transport { float x, y; public: explicit Ship(double x_, double y_) { x = (float) x_, y = (float) y_; } explicit Ship(float x_, float y_) { x = x_, y = y_; } ~Ship() = default; void deliver() override { printf("Ship::deliver()\n"); } friend std::ostream &operator<<(std::ostream &os, const Ship &o) { return os << "x: " << o.x << " y: " << o.y; } static std::unique_ptr<Ship> create(float r_, float theta_) { return std::make_unique<Ship>(r_ * cos(theta_), r_ * sin(theta_)); } };} // namespace hicc::dp::factory::innervoid test_factory_inner() { using namespace hicc::dp::factory::inner; auto p1 = create_transport<Trunk>(3.1, 4.2); std::cout << *p1.get() << '\n'; p1->deliver(); auto p2 = create_transport<Ship>(3.1, 4.2); std::cout << *p2.get() << '\n'; p2->deliver(); auto p3 = Ship::create(3.1, 4.2); std::cout << *p3.get() << '\n'; p3->deliver();}依照古典的表述,工厂办法模式倡议应用非凡的工厂办法代替对于对象构造函数的间接调用 (即应用 new运算符)。 不必放心, 对象仍将通过 new运算符创立, 只是该运算符改在工厂办法中调用罢了。 工厂办法返回的对象通常被称作 “产品”。 ...

August 28, 2021 · 6 min · jiezi

关于c++:逆向基础软件手动脱壳技术入门

前言:大家好,我是周杰伦 这里整合了一下之前本人学习软件手工脱壳的一些笔记和脱文,心愿能给新学软件逆向和脱壳的童鞋们一点帮忙。 1 一些概念1.1 加壳加壳的全称应该是可执行程序资源压缩,是爱护文件的罕用伎俩。加壳过的程序能够间接运行,然而不能查看源代码。要通过脱壳才能够查看源代码。 加壳是利用非凡的算法,对EXE、DLL文件里的资源进行压缩、加密。相似WINZIP 的成果,只不过这个压缩之后的文件,能够独立运行,解压过程齐全荫蔽,都在内存中实现。它们附加在原程序上通过Windows加载器载入内存后,先于原始程序执行,失去控制权,执行过程中对原始程序进行解密、还原,还原实现后再把控制权交还给原始程序,执行原来的代码局部。加上外壳后,原始程序代码在磁盘文件中个别是以加密后的模式存在的,只在执行时在内存中还原,这样就能够比拟无效地避免破解者对程序文件的非法批改,同时也能够避免程序被动态反编译。 壳的类型通常分为压缩壳和加密壳两类。压缩壳的特点是减小软件体积大小,加密爱护不是重点。加密壳品种比拟多,不同的壳侧重点不同,一些壳单纯爱护程序,另一些壳提供额定的性能,如提供注册机制、应用次数、工夫限度等。 1.2 OEPOEP:(Original Entry Point),程序的入口点。软件加壳个别暗藏了程序实在的OEP(或者用了假的OEP), 咱们须要寻找程序真正的OEP,才能够实现脱壳。 个别加壳程序在应用Ollydbg等动静调试工具时,会停在壳的预处理块。即处在对于程序原始代码块的解压或解密操作之前,在运行完程序自脱壳模块后,会停留在程序加壳之前的OEP地位,此时是dump程序的最佳时期。脱壳时在实在OEP处下int3断点,就能够捕捉到程序代码段完全恢复的状态。因而,寻找加壳程序的正确OEP,也成了手动脱壳时的第一要务。 1.3 IATIAT:(Import Address Table),导入地址表。因为导入函数就是被程序调用但其执行代码又不在程序中的函数,这些函数的代码位于一个或者多个DLL中。当PE文件被装入内存的时候,Windows装载器才将DLL 装入,并将调用导入函数的指令和函数理论所处的地址分割起来(动静连贯),这操作就须要导入表实现。其中导入地址表就批示函数理论地址。少数加壳软件在运行时会重建导入地址表,因而获取加壳程序正确的导入地址表也是手动脱壳操作中的一个关键问题。 2 一些脱壳办法2.1单步跟踪法单步跟踪法的原理就是通过Ollydbg的单步(F8)、单步进入(F7)和运行到(F4)性能,残缺走过程序的自脱壳过程,跳过一些循环复原代码的片段,并用单步进入确保程序不会略过OEP。这样能够在软件主动脱壳模块运行结束后,达到OEP,并dump程序。 2.2 ESP定律法ESP定律法是脱壳的利器,是利用频率最高的脱壳办法之一。 ESP定律的原理在于程序中堆栈均衡的正当利用。因为在程序自解密或者自解压过程中,不少壳会先将以后寄存器内容压栈,如应用pushad,在解压完结后,会将之前的寄存器值出栈,如应用popad。因而在寄存器出栈时,往往程序代码被主动复原,此时硬件断点触发。而后在程序以后地位,只须要少许单步跟踪,就很容易达到正确的OEP地位。 2.3内存镜像法(二次断点法)内存镜像法是在加壳程序被加载时,通过OD的ALT+M快捷键,进入到程序虚拟内存区段。而后通过加两次内存一次性断点,达到程序正确OEP的地位。 内存镜像法的原理在于对于程序资源段和代码段下断点,个别程序自解压或者自解密时,会首先拜访资源段获取所需资源,而后在主动脱壳实现后,转回程序代码段。这时候下内存一次性断点,程序就会停在OEP处。 2.4一步达到OEP所谓的一步达到OEP的脱壳办法,是依据所脱壳的特色,寻找其间隔OEP最近的一处汇编指令,而后下int3断点,在程序走到OEP的时候dump程序。如一些压缩壳往往popad指令间隔OEP或者Magic Jump特地近,因而应用Ollydbg的搜寻性能,能够搜寻壳的特色汇编代码,达到一步断点达到OEP的成果。 2.5最初一次异样法最初一次异样法的原理是,程序在自解压或自解密过程中,可能会触发无数次的异样。如果能定位到最初一次程序异样的地位,可能就会很靠近主动脱壳实现地位。当初最初一次异样法脱壳能够利用Ollydbg的异样计数器插件,先记录异样数目,而后从新载入,主动停在最初一次异样处。 2.6 模仿跟踪法模仿跟踪法的原理就是应用Ollydbg下条件断点,SFX相当于是一个自解压段,在自解压段完结时(eip的值转到代码段时),曾经间隔OEP很近,然而这种跟踪办法会比拟耗时。 2.7 “SFX”法“SFX”法利用了Ollydbg自带的OEP寻找性能,能够抉择间接让程序停在OD找到的OEP处,此时自解压曾经实现,能够间接dump程序。 3一些脱壳实际上面给出整顿的应用以上办法,本人尝试手动脱这几种罕用壳的脱壳笔记。 3.1UPX脱壳笔记首先进行侦壳: 首先把程序扔到OllyIce外面能够看到: 而后这里尝试应用ESP定理:即在ESP第一次扭转时,对ESP的地址设置硬件字拜访断点,这样能够在代码被UPX算法还原之后,跳转到程序的失常入口处。 而后F5运行,并没有间接到跳转到程序入口处的大跳地位,然而能够看到UPX的大跳就在眼前: 所以被还原后的程序入口点就是0x00445151(通过单步往下走,F4略过往回走的循环语句,也能够看到这个大跳的地位。)接下来走到大跳地位,跳到失常程序入口处: 而后去掉硬件断点,并应用LoadPE的dump性能dump目标程序: 先修改映像大小,而后再抉择残缺脱壳,这样能够失去第一步dump的程序,而后再应用ImportREC修复dump程序的OEP,OEP的信息通过OD自带的dump性能查问或者间接填45151: 将正确的入口地址填入ImportREC中,而后主动搜寻IAT信息: 而后点击获取输出表失去修改IAT之后的程序函数输出表,而后再点击显示有效函数,欢快地发现没有有效函数,那么就能够间接修复转存文件了。 抉择刚刚第一步dump下来的转储文件进行修复,修复实现之后脱壳实现: 这里对于压缩壳UPX,间接应用了ESP定律,能够很不便找到OEP并dump程序。 4.2 tElock脱壳笔记这里脱的是一个tElock的壳: 1、先应用最简略的最初一次异样法:首先把程序扔到OllyIce外面设置OD调试选项中的异样选项, 仅保留内存非法拜访异样,而后应用异样计数器插件,在应用前要清空断点设置: 等到程序失常运行后,从新加载程序,再抉择第二步,停在最初一次异样之前: 而后用Alt+M转到内存窗口,对主程序code段下内存断点,SHIFT+F9执行: 这样程序就中断在了正确的OEP处,能够抉择从模块中删除剖析以显示失常剖析的汇编代码。而后应用LoadPE dump程序,并修改程序映像大小。然而在应用ImportREC v1.6F Fix版,输出正确的OEP,获取函数输出表信息时,会发现有效的指针。应用办法一修复后,再应用办法三能够齐全修复 ...

August 27, 2021 · 1 min · jiezi

关于c++:技术实践|网易云信-IM-SDK-服务高可用技术方案

导读:“域名劫持是互联网攻打的一种形式,通过攻打域名解析服务器(DNS),或伪造域名解析服务器(DNS)的办法,把指标网站域名解析到谬误的 IP 地址从而实现用户无法访问指标网站的目标 , 或者蓄意 / 歹意要求用户拜访指定 IP 地址(网站)的目标 。 ”(以上内容引自 「 域名劫持 」百度百科 ) 。网易云信 IM SDK 作为一款 ToB 产品,撑持着各种三方业务的发展。面对各种简单的网络环境,DNS 劫持与 DNS 净化时有发生,那么在咱们提供服务的过程中应该如何防止此类事变的产生呢? 文|郝魁 网易云信资深 C++ 开发工程师 技术是一把双刃剑,在大侠手中定国安邦,在鼠辈手中祸国殃民。 “域名劫持”尽管带了“劫持”二字,但在此环境中实属中性词汇。例如对于一些非法网站的拜访,能够通过 DNS 服务把相应的域名解析到不可拜访的 IP 地址,以阻止对于该非法网站的拜访并给予正告等。在网易云信即时通信产品运维过程中,已经产生过服务域名“netease.im”被居心叵测的人或组织歹意劫持的事件,导致接入网易云信 IM SDK 的利用无奈失常登录,给客户以及客户的用户造成影响。为了弄清楚这种事变是怎么产生的,咱们来剖析一下网易云信 IM SDK 的登录过程:从流程上来看,在“更新 LBS”的节点上,如果产生 DNS 劫持,在拜访网易云信 LBS 服务时有可能超时或者拿到了谬误的应答,导致 IM SDK 无奈获取失常的 Link 服务器地址及端口,如何防止此类事变的产生呢?本文将围绕网易云信端侧服务高可用技术计划以及高可用组件实现计划进行具体分享。 一、如何预防 DNS 劫持 通常对于域名被劫持后,咱们能够采纳以下几种形式:上述几种形式,都是在产生劫持后采取的计划,无论是从服务提供侧还是服务应用侧来说都不够灵便,为了解决这些问题,提前预防事变的产生,咱们次要采纳以下两种计划:其中接入了 HttpDNS 服务的计划升高了所有场景下域名被劫持的危险。 1、LocalDNS域名劫持 域名劫持始终是困扰许多开发者的问题之一,其体现为域名 A 应该返回的 DNS 解析后果 IP1 被歹意替换为了 IP2,导致 A 的拜访失败或拜访了一个不平安的站点,常见域名劫持形式有以下几种: 黑客入侵宽带路由器,篡改终端用户 LocalDNS,并指向伪造 LocalDNS,通过管制 LocalDNS 的逻辑返回谬误的 IP 信息进行域名劫持。 ...

August 26, 2021 · 2 min · jiezi

关于c++:为什么返回一个临时对象的引用是不安全的

1.问题阐明返回一个长期对象的援用是不平安的,因为当来到作用域,这个长期对象会马上析构,所以函数返回的总是悬挂援用(空悬援用),应用这个援用是一个未定义行为,会导致程序解体。2.问题剖析看上面这段代码: const int&retRef(){ return 1180;} const int&k = retRef();std::cout<<k<<std::endl;此时打印k,就是一个未定义行为,因为,1180的援用所指对象曾经被销毁了(援用其实只是常量指针)。这个很容易辨认。然而,这里实际上隐含一个只能指针的坑。上面这段代码其实也是不平安的: const std::shared_ptr<int>& retRef(){ return nullptr;}智能指针也是一个对象,返回nullptr,编译器会结构一个长期对象,并用拷贝构造函数吧null复制进去,此时,会产生和下面那段代码一样的问题。如果此时,调用这个函数,其实也是未定义行为。

August 25, 2021 · 1 min · jiezi

关于c++:高性能-C-HTTP-客户端原理与实现

一、什么是Http ClientHttp协定,是全互联网独特的语言,而Http Client,能够说是咱们须要从互联网世界获取数据的最根本办法,它实质上是一个URL到一个网页的转换过程。而有了根本的Http客户端性能,再搭配上咱们想要的规定和策略,上至内容检索下至数据分析都能够实现了。 继上一次介绍用Workflow能够10行C++代码实现一个高性能Http服务器,明天持续给大家用C++实现一个高性能的Http客户端也同样很简略! // [http_client.cc]#include "stdio.h"#include "workflow/HttpMessage.h"#include "workflow/WFTaskFactory.h"int main (int argc, char *argv[]){ const char *url = "https://github.com/sogou/workflow"; WFHttpTask *task = WFTaskFactory::create_http_task (url, 2, 3, [](WFHttpTask * task) { fprintf(stderr, "%s %s %s\r\n", task->get_resp()->get_http_version(), task->get_resp()->get_status_code(), task->get_resp()->get_reason_phrase()); }); task->start(); getchar(); // press "Enter" to end. return 0;}只有装置好了Workflow,以上代码即能够通过以下命令编译出一个简略的http_client: g++ -o http_client http_client.cc --std=c++11 -lworkflow -lssl -lcrypto -lpthread依据Http协定,咱们执行这个可执行程序 ./http_client,就会失去以下内容: HTTP/1.1 200 OK同理,咱们还能够通过其余api来取得返回的其余Http header和Http body,所有内容都在这个 WFHttpTask 中。而因为Workflow是个异步调度框架,因而这个工作收回之后,不会阻塞以后线程,外加外部自带的连贯复用,从根本上保障了咱们的Http Client的高性能。 接下来给大家具体解说一下原理~ 二、申请的过程1. 创立Http工作上述demo能够看到,申请是通过发动一个Workflow的Http异步工作来实现的,创立工作的接口如下: WFHttpTask *create_http_task(const std::string& url, int redirect_max, int retry_max, http_callback_t callback);第一个参数就是咱们要申请的URL。对应的,在一开始的示例中,咱们的重定向次数redirect_max是2次,而重试次数retry_max是3次。第四个参数是一个回调函数,示例中咱们用了一个lambda,因为Workflow的工作都是异步的,因而咱们处理结果这件事件是被动告诉咱们的,后果回来就会调起这个回调函数,格局如下: ...

August 25, 2021 · 1 min · jiezi

关于c++:C中析构函数为什么不允许抛出异常

1.问题自身:在语法上,C++容许在析构中抛出异样,但异样解决,自身就是为了解决结构失败的状况。当一个对象结构失败而抛出异样时,咱们该当利用析构函数,清理有效对象,并回收其资源,这是使程序强壮的重要伎俩。2.问题剖析:从1可知,构造函数显然是能够抛出异样的。进一步剖析,在析构函数中抛出异样,会呈现哪些状况:(1)对象失常完结,在析构时,触发析构函数中的异样,打印异样信息,退出。在这种状况下,抛出异样并没有什么问题,析构函数的异样会被里面捕捉;当然,如果里面的程序没有持续开释残余的资源,可能会造成内存泄露。(2)对象来到作用域之前,抛出异样,此时会调用析构函数,析构函数再抛出异样,此时之前的异样就不能被捕捉了,而且会造成程序crash。3.问题总结:那么,是否就不能够在析构函数中应用异样?答案显然是否,在某些状况下,咱们不可避免的要在析构函数中应用异样,使程序仍然强壮的要害的关键在于,不要让异样逃离析构函数。能够用try catch吞掉异样。当然,更好的实际是,就不要在析构函数中应用异样。

August 24, 2021 · 1 min · jiezi

关于c++:Qt-自定义组件滑动窗口

仓库 桌面背景切换 桌面背景放弃 个性反对小部件追加反对获取小部件的数量反对获取以后小部件的索引和小局部地址反对查问给定的小部件索引反对设置首页小部件反对小部件移除反对背景图片是否可滑动切换 !!!#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QWidget>#include <QScrollArea>#include <QHBoxLayout>#include <QScroller>#include <QTimer>#include <QPropertyAnimation>/* 滑动窗口 * 1. 反对小部件追加 * 2. 反对获取小部件的数量 * 3. 反对获取以后小部件的索引和小局部地址 * 4. 反对查问给定的小部件索引 * 5. 反对设置首页小部件 * 6. 反对小部件移除 * 7. 反对背景图片是否可滑动切换 !!! * SliderWidget(QWidget *parent = nullptr, const QString &picture = ""); * 当 picture 传入图片地址时, 背景图片将始终放弃不可切换 */class SliderWidget : public QWidget{ Q_OBJECTpublic: SliderWidget(QWidget *parent = nullptr, const QString &picture = ""); ~SliderWidget(); int addWidget(QWidget *page); int count() const; int currentIndex() const; QWidget *currentWidget() const; int indexOf(QWidget *widget) const;public slots: void setCurrentIndex(int index); void setCurrentWidget(QWidget *widget); void removeWidget(int index); void removeWidget(QWidget *widget);protected: void resizeEvent(QResizeEvent *ev) override;protected slots: void onScrollerStateChanged(QScroller::State state); void onSliderTimerTimeout();signals: void currentChanged(int index);private: void initUi(); void initCtrl(); void updateIndicator(int index);private: QWidget *m_pMainWidget; QScrollArea *m_pScrollArea; QHBoxLayout *m_pMainLayout; QWidget *m_pIndicatorWidget; QHBoxLayout *m_pIndicatorLayout; QPropertyAnimation *m_pAnimation; QTimer *m_pSlidingTimer; bool m_sliderFlag = false; int m_sliderPressedValue = 0; int m_sliderReleaseValue = 0; int m_curPageIndex = -1; int m_nextPageIndex = -1; QString m_background;};#endif // MAINWINDOW_H

August 24, 2021 · 1 min · jiezi

关于c++:issue-pure-virtual-method-called-虚函数调用段错误

1.问题形容: 在做一个分布式存储的服务器。服务器在某些异样敞开的场景下,会在析构时,报错:pure virtual method called, terminate called without an active exception。服务器析构时,会调用上面这行代码:`tx->Commit();` // std::shared_ptr<SeGhBacken> tx;其申明为:基类:class SeGhDB {public: virtual int Commit();}申明:class SeGhBacken : public SeGhDB { int Commit() override;}之后服务器会段谬误,并报错:pure virtual method called, terminate called without an active exception2.问题剖析: 段谬误,根本都是内存问题。个别是指针被置空,或是指针所指对象曾经生效,此处也不例外。这个谬误的起因为:在运行期,子类对象被以前析构,或者基本未被结构进去。调用这个函数实现的时候,编译器就调用到了基类的虚函数,如果基类的虚函数未实现,则会报上述谬误。3.问题解决 对象提前被析构或未被结构,通常是因为多线程环境下,线程调度引起的。遇到上述问题,应该首先查看线程内资源的结构和回收情况。题主遇到的这个问题,正是由此导致。在本我的项目线程池实现中,遇到退出信号,会摈弃后续工作,导致对象没有被正确结构,从而造成了这个问题,在调整了线程池参数后,问题失去解决。4.总结: 此问题个别解决方案:(1)应用new和delete治理对象内存,本人手动管制对象生命周期;(2)线程内实现对象全生命周期治理,在一个线程内实现对象的结构、调用和析构;(3)对于同一个线程内的对象,要恪守谁申请,谁开释的内存治理标准;(4)禁止多级继承。

August 23, 2021 · 1 min · jiezi

关于c++:C标准库文件系统

1. 门路 应用 std::filesystem::path 类来示意文件门路. #include <iostream>#include <filesystem>namespace fs = std::filesystem;int main(){ fs::path p1("E:\\"); fs::path p2(p1 / "Program Files (x86)" / "Tesseract-OCR"); std::cout << p2; // 判断门路是否存在 if (fs::exists(p2)) { std::cout << " exists.\n"; } else { std::cout << " does not exists.\n"; }}"E:\\Program Files (x86)\\Tesseract-OCR" exists.获取、切换当前工作门路: #include <iostream>#include <filesystem>namespace fs = std::filesystem;int main(){ // 打印当前工作门路 std::cout << fs::current_path() << '\n'; // 切换当前工作门路 fs::current_path(fs::path("C:\\")); std::cout << fs::current_path() << '\n';}"E:\\repos\\data-structure\\data-structure""C:\\"2. 文件信息 ...

August 22, 2021 · 4 min · jiezi

关于c++:C线程池

1. Boost.Asio 线程池 下载:https://sourceforge.net/proje... VS 中应用:我的项目 - 属性 - VC目录 - 蕴含目录,增加 YourPath\asio-1.18.2\include 官网文档:https://www.boost.org/doc/lib... #include <iostream>#include <atomic>#include <asio.hpp>using namespace std::literals;static std::atomic_uint32_t count = 0;int main(){ // 两个线程 asio::thread_pool pool(2); auto work = []() { std::this_thread::sleep_for(1ns); count++; }; int n = 1000; for (int i = 0; i < n; i++) { // 提交工作 asio::post(pool, work); } // 期待所有线程执行实现 pool.join(); std::cout << "count = " << count << '\n';}count = 1000其余操作: ...

August 21, 2021 · 2 min · jiezi

关于c++:C模板部分特化

1. 简介 局部特化(partial specialization)容许为给定类别的模板实参自定义类模板和变量模板. 2. 语法 template<parameter-list> class ClassName<argument-list> declaration其中,argument-list 能够蕴含具体的类型(对应类型参数)、具体的值(对应非类型参数),也能够蕴含在 <parameter-list> 中指定的模板形参. 如, // primary templatetemplate<class T1, class T2, int I>class A {};// #1: partial specialization where T2 is a pointer to T1template<class T, int I>class A<T, T*, I> {};// #2: partial specialization where T1 is a pointertemplate<class T, class T2, int I>class A<T*, T2, I> {};// #3: partial specialization where T1 is int, I is 5, and T2 is a pointertemplate<class T>class A<int, T*, 5> {}; // #4: partial specialization where T2 is a pointertemplate<class X, class T, int I>class A<X, T*, I> {};具体例子:移除援用 ...

August 21, 2021 · 2 min · jiezi

关于c++:C模板完全特化

1. 简介 齐全特化(full specialization)也叫显式特化(explict specialization). 它容许为给定的模板实参自定义模板代码. 2. 语法 template <> declaration必须实例化所有的模板形参. 如, #include <iostream>template <typename T>struct IsVoid{ static constexpr bool value = false;};template <>struct IsVoid<void>{ static constexpr bool value = true;};int main(){ std::cout << std::boolalpha << IsVoid<int>::value << '\n'; // false std::cout << std::boolalpha << IsVoid<void>::value << '\n'; // true}3. 什么时候不须要加上 template <>? (1)如果你正在显式特化一个模板,则应该加上 template <>. template<class T> class Array { /*...*/ };// primary templatetemplate<class T> void sort(Array<T>& v);// specialization for T = inttemplate<> void sort(Array<int>&);template<typename T>struct A { struct B {} template<class U> struct C { };};template <>struct A<int> { void f(int);};(2)如果你正在为一个已显式特化的类模板定义成员,则不须要加上 template <>. ...

August 21, 2021 · 1 min · jiezi

关于c++:C模板参数包

1. 简介 模板参数包是承受零个或多个模板参数(非类型、类型或模板)的模板参数。函数参数包是承受零个或多个函数参数的函数参数。 2. 语法 (1) 非类型模板参数包: Type... Args此处 Type 为具体的类型,如 int. (2) 类型模板参数包: typename... Types(3) 模板模板参数包:(即模板形参是另一个模板) template <parameter-list> typename... Types(4) 函数参数包: Types... Args(5) 参数包扩大: pattern...将 pattern 扩大为以逗号分隔的列表(蕴含0或多个模式). 其中,pattern 必须蕴含至多一个参数包. 在类模板中,模板参数包需是最初一个模板形参. 而在函数模板中则不用(指的是在模板形参列表中的地位,而不是函数形参列表),只有可能从函数实参列表推断出参数包即可. template<typename... Ts, typename U> struct Invalid; // Error: Ts.. not at the end template<typename... Ts, typename U, typename=void>void valid(U, Ts...); // OK: can deduce U// void valid(Ts..., U); // Can't be used: Ts... is a non-deduced context in this position从上例中能够看出,即便是在函数模板中,参数包仍须要是函数形参列表的最初一个参数. 简略起见,尽量将参数包放在最初. ...

August 20, 2021 · 3 min · jiezi

关于c++:C完美转发

1. std::forawrd std::forward<T>(arg) 能够实现完满转发,即如果 arg 是一个右值援用,则转发之后后果仍是右值援用;反之,如果 arg 是一个左值援用,则转发之后后果仍是左值援用. #include <iostream>struct BigObject{ char data[1 << 10];};void g(BigObject& o){ std::cout << "lvalue reference\n";}void g(BigObject&& o){ std::cout << "rvalue reference\n";}template <typename T>void f(T&& arg){ g(std::forward<T>(arg));}int main(){ BigObject o; f(o); f(BigObject());}lvalue referencervalue reference2. 为什么须要完满转发? 在函数模板编程中,常有一种场景是应用模板参数去调用另一个函数(如,上例中 f 去调用 g),这时候如果只提供值传递版本会显得效率太低。函数的参数个别会尽可能地设为援用类型,以防止对象拷贝带来的昂扬开销.为了使一个函数既能够承受左值,又能够承受右值,C++11 之前的解决方案是将参数类型设为 const Type&. 但这并不是很不便,如限度了参数是常量.如果函数 g 既提供了左值援用版本和右值援用版本,则最好的状况是函数 f 能够依据参数类型去调用相应版本的 g. 而完满转发正能够满足此要求.3. 援用折叠规定 右值援用和右值援用叠加将失去右值援用;右值援用和左值援用叠加将失去左值援用;左值援用和左值援用叠加将失去左值援用.template <typename T>using TR = T&; // v 的类型TR<int> v; // int&TR<int>& v; // int&TR<int>&& v; // int&template <typename T>using TRR = T&&; // v 的类型TRR<int> v; // int&&TRR<int>& v; // int&TRR<int>&& v; // int&&4. 完满转发的原理 ...

August 20, 2021 · 2 min · jiezi

关于c++:BoostAsio使用协程进行网络编程

简介 本文基于 Boost.Asio 编写一个 TCP echo 程序. 且应用协程来解决异步逻辑. Asio 下载:https://sourceforge.net/proje... VS 中应用:我的项目 - 属性 - VC目录 - 蕴含目录,增加 YourPath\asio-1.18.2\include 官网文档:https://www.boost.org/doc/lib... 1. 头文件及全局变量 #include <iostream>#include <thread>#include <mutex>#include <chrono>#include <string>#include <asio.hpp>#include <asio/ts/buffer.hpp>#include <asio/ts/internet.hpp>using asio::ip::tcp;static std::mutex coutLock;// 简略起见,此处回显固定的音讯static std::string Message("hello, asio!");static size_t MsgLength = Message.size();2. TcpServer // 异步class TcpServer{public: TcpServer(asio::io_context& context, uint16_t port) : m_context(context), m_acceptor(context, tcp::endpoint(tcp::v4(), port)) { waitForConnection(); }private: asio::awaitable<void> waitForConnection() { while (true) { tcp::socket socket(m_context); co_await m_acceptor.async_accept(socket, asio::use_awaitable); coutLock.lock(); std::cout << "New Connection From: " << socket.remote_endpoint() << '\n'; coutLock.unlock(); // 创立协程,解决新到的连贯 asio::co_spawn(socket.get_executor(), handleConnection(std::move(socket)), asio::detached); } } static asio::awaitable<void> handleConnection(tcp::socket&& socket) { std::vector<uint8_t> buffer(MsgLength); try { while (true) { std::size_t n = co_await asio::async_read(socket, asio::buffer(buffer), asio::use_awaitable); co_await asio::async_write(socket, asio::buffer(buffer, n), asio::use_awaitable); } } catch (const std::exception& e) { std::lock_guard<std::mutex> lock(coutLock); std::cerr << "Handle Connection Error: " << e.what() << '\n'; } }private: asio::io_context& m_context; tcp::acceptor m_acceptor;};此时不必再传入回调函数,而是将回调函数替换为 asio::use_awaitable,而后再 co_await async_xxx(...); 即可. ...

August 20, 2021 · 2 min · jiezi

关于c++:C协程

协程就是一个可挂起可复原执行的函数. C++ 中的协程是无栈式的:当协程被挂起时,它将返回到调用者,且复原执行所须要的相干数据并不保留在栈上. 协程的益处是: 容许以串行的形式编写异步执行的代码,而无需显式应用回调;能够实现惰性计算(如,生成器).1. 协程 一个函数只有蕴含如下之一便是协程: 应用 co_await 运算符来挂起执行; size_t n = co_await socket.async_read_some(buffer(data));应用 co_yield 关键字来挂起执行,并返回一个值; co_yield n++;应用 co_return 关键字来完结执行,并可选地返回一个值. co_return;co_return 7;2. co_await co_await 运算符的操作数必须是 Awaitable. 一个对象如果有如下3个成员函数,则它就是 Awaitable: await_ready:协程开始时会调用此函数,如果返回 true,示意你想得到的后果曾经失去了,协程不须要执行了. 所以大部分状况这个函数的实现是要返回 false.await_suspend:执行 co_await Awaitable 时便会执行此函数,它会挂起协程. 该函数会传入一个 coroutine_handle 类型的参数,这是一个由编译器生成的变量. 在此函数中调用 handle.resume() 就能够复原协程.await_resume:复原协程运行时便会调用此函数. 这个函数的返回值就是 co_await 运算符的返回值.3. promise_type 设协程的返回值类型为 Task,则 Task 必须蕴含一个外部类 promise_type,且 promise_type 须要蕴含如下成员函数: struct promise_type { /* 结构协程的返回值 */ Task get_return_object() { return Task{}; } /* 在执行协程体之前调用 */ std::suspend_never initial_suspend() { return std::suspend_never{}; } /* 在执行完协程体之后调用 */ std::suspend_never final_suspend() noexcept { return std::suspend_never{}; } /* 执行 co_return; 时调用 只需定义 return_void 或 return_value 其中之一便可 */ void return_void() {} /* 执行 co_return value; 时调用 */ void return_value(T value) { // ... } /* 执行 co_yield value; 时执行 如果不须要用到 co_yield,则无需定义 */ auto yield_value(T value) { // ... return std::suspend_always{}; } /* 异样解决 */ void unhandled_exception() {}};4. 例子1:应用协程来解决异步逻辑 ...

August 20, 2021 · 3 min · jiezi

关于c++:C模板concept

束缚指定了模板实参须要满足的要求,而 concept 则是束缚的命名汇合. 1. concept template <template-parameter-list>concept concept-name = constraint-expression; 尔后 concept-name 能够取代 typename 来申明模板形参以增加束缚.也能够将 concept-name<template-parameter-lis> 作为束缚表达式的一部分. 2. 束缚 束缚能够是一个原子束缚,或两个束缚的逻辑与运算(&&),或两个束缚的逻辑或运算(||). 原子束缚只蕴含一个表达式,且该表达式的值的类型须要为 bool(不能通过类型转换). 如果表达式的值为 true,则满足束缚,否则不满足束缚. template <typename T>requires std::is_arithmetic<T>::valueT add(T x, T y){ return x + y;}int main(){ int i = add(1, 2); double d = add(1.2, 3.4); // error // std::string s(add(std::string("111"), std::string("222")));}此处应用 requires 从句(区别于 requires 表达式)来要求 T 必须满足 std::is_arithmetic<T>::value 为 true. 等价于, template <typename T>concept Arithmetic = std::is_arithmetic<T>::value;template <Arithmetic T>T add(T x, T y){ return x + y;}束缚的逻辑运算: ...

August 20, 2021 · 2 min · jiezi

关于c++:使用QGraphicsItem自定义同心圆旋转矩形和箭头等Item框体组件

1、背景在视觉我的项目开发过程中碰到了图像显示和ROI矩形框或其余框体的显示的需要,最早我在开发过程中间接将Halcon的显示窗口间接贴在Qt的控件上,这样就省去了图像转换后再绘图的操作(Halcon具备独特的图像格式HObject),然而Halcon没有图层的概念,只有create_drawing_object_circle这些算子能够应用,但这些在图像实时刷新的时候比拟耗时且也没有图层能够操作(Win环境实时成果还行,Linux下较难实现实时成果),采纳Qpixmap显示在UI端,并应用QGraphicsItem来实现自定义的图形显示需要,成果比应用Halcon窗口显示要好很多,本篇就如何实现自定义的QGraphicsItem开发实现各种图形的显示进行开展。 2、成果展现目前依据需要,给出了如下图所示的图形的自定义成果,能够依据须要创立不同形态的图形框: 3、自定义创立同心圆3.1 同心圆的创立首先在创立的同心圆结构类里,有中心点,两个圆半径,以及两个圆上的Edge点(用于拖动扭转圆大小),其类的定义如下 // 同心圆class BConcentricCircle : public BCircle{public: BConcentricCircle(qreal x, qreal y, qreal radius1, qreal radius2, ItemType type); enum { Type = 22}; int type() const { return Type; } void updateOtherRadius(); void setAnotherEdge(QPointF p);protected: virtual QRectF boundingRect() const override; virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;public: QPointF m_another_edge; qreal m_another_radius;};同心圆的策略是在圆的根底上再画一个圆,所以在其构造函数中要先去定义同心圆的几个点-圆心、圆上边缘点。 BConcentricCircle::BConcentricCircle(qreal x, qreal y, qreal radius1, qreal radius2, ItemType type) : BCircle(x, y, radius1, type), m_another_edge(x+radius2*sqrt(2)/2, y+radius2*sqrt(2)/2){ BPointItem *point = new BPointItem(this, m_another_edge, BPointItem::Special); point->setParentItem(this); m_pointList.append(point); m_pointList.setRandColor(); updateOtherRadius();}由构造函数可知,同心圆是由一个圆和另一个圆组成,其蕴含BCircle(x, y, radius1, type),再以圆心和m_another_edge(x+radius2sqrt(2)/2, y+radius2sqrt(2)/2)去画另一个圆。其余局部实现如下: ...

August 17, 2021 · 3 min · jiezi

关于c++:new与malloc以及free-store与heap搬运理解与整理

自在存储区和堆placement-new、new operator、operator new 区别demo1:operator new/operator delete应用new 与 malloc自在存储区和堆参考:https://stackoverflow.com/que...参考:https://www.quora.com/What-is...参考:https://www.cnblogs.com/qg-wh...参考:https://blog.csdn.net/nie1994...两种动态内存区域。 heapfree store C++的内存布局堆(malloc/free)、栈、自在存储区(new delete)、全局/动态存储区、常量存储区free store 和 heap的区别(语言背景角度)malloc在堆上调配的内存块,应用 free 开释内存,而 new 所申请的内存则是在自在存储区上,应用 delete 来开释 精确来说free store 对应的是 operator newfree store 和 headp是不同内存区域吗(操作系统角度)多角度探讨异同(编译器上)大部分C++编译器默认应用堆来实现自在存储。也就是说这个时候说它是在堆上还是在自在存储区上都对。(语言背景)堆是C或操作系统概念。自在存储区是C++形象进去的逻辑概念。 C++提出该概念更加强调了这两种内存自在调配不应该被互操作,且C++使得内存自在调配更加灵便(placement-new)。C++中应用 malloc 和 free 在技术上是可能的(偶然有用),但这种做法应该防止或至多是孤立的。(程序角度) free store:对象的生命周期 能够小于 调配存储空间的工夫(即free store能够在不立刻初始化的状况下分配内存,并且能够再不立刻开释内存的状况下销毁对象)heap:尽管默认的全局 new 和 delete (注:特指::operator new)可能由特定编译器依据 malloc 和 free 实现,但堆与闲暇存储不同,并且在一个区域(heap or free store)中调配的内存不能在另一个区域中平安地开释。 从堆(malloc进去的)中的内存能够用placement-new结构和显式析构,这样的话对于free store对象生存期的阐明再这里也实用。placement-new、new operator、operator new参考:https://blog.51cto.com/yiluoh...*参考:https://www.cnblogs.com/luxia...区别new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数。(注:不是很精确,然而很帮忙了解)new operator(操作符) 作用:调配足够的空间(调用 operator new),并且调用对象的构造函数执行过程: 调用operator new分配内存调用构造函数生成类对象返回相应指针重载:不能够被重载new operator与delete operator的行为是不可能也不应该被扭转,这是C++规范作出的承诺operator new(函数) 作用:分配内存,但不执行结构重载:能够重载。 ...

August 17, 2021 · 2 min · jiezi

关于c++:从0搭建在线聊天室只需4步

从0搭建在线聊天室,只需4步!聊天室不同于单聊和群聊,是一类集成了多种 IM 性能一体的大规模实时音讯散发零碎。在跨入新世纪的2000年,聊天室作为新型的即时通讯场景迅速在年轻人群体中炽热起来, “网易聊天室”“碧海银沙” 引领了过后语音聊天的热潮。 时至今日,聊天室的势头也不减当年,宽泛使用于在线 KTV 、连麦开黑、主播 PK 、在线秀场等场景,还具备文本、表情、点赞、撒花等互动形式,架起沟通桥梁的同时,玩法也更加多变。 本期云信小课堂就教大家如何疾速集成聊天室,并实现进出聊天室、简略的音讯收发、权限治理等性能。 视频解说https://www.bilibili.com/vide... 集成聊天室-根底篇Step1 初始化并进入聊天室进入聊天室能够有两种形式:以独立模式进入聊天室和非独立模式进入聊天室。 独立模式是指 在IM处于未登录的状况下,进入聊天室的形式,针对只须要聊天室性能的业务场景。请引入NIM_Web_Chatroom_*.js,并通过 Chatroom.getInstance({...}) 来初始化聊天室实例。非独立模式是指 先实现IM登录,再进入聊天室的形式,针对须要IM和聊天室性能的业务场景。请引入 NIM_Web_SDK_*.js,并请通过 SDK.NIM.getInstance({...}) 和SDK.Chatroom.getInstance({...})来别离初始化 IM 和 聊天室的实例这里为了不便演示,抉择独立模式: Step2 收发音讯进入聊天室胜利后能力发送/接管音讯 Step3 权限治理聊天室成员治理和聊天室信息查问 Step4 来到聊天室来到或者切换聊天室 集成聊天室-Demo篇Step1 下载DemoDemo链接:https://github.com/netease-ki...,下载到本地,解压后通过IDE关上,下载期间,率先获取APP_KEY; 如何获取APP_KEY? 如果曾经是网易云信开发者,能够间接从网易云信的管制后盾获取APP_KEY; 如果是第一次体验,则须要返回网易云信官网(http://163.lu/f04GM3)注册云信账号-创立利用-点击App_Key治理即可获取相干信息。 Step2 运行Demo在NIM_Web_Demo-master\webdemo\imNew\js\config.js 外面输出对应环境的appkey,而后在demo根目录下执行npm install 和node app命令 Step3 体验Demo性能关上http://127.0.0.1:8182/webdemo...地址体验demo性能;(倡议先登录账号) demo中实现收发音讯、禁言、拉黑等相干性能的代码在NIM_Web_Demo-master\webdemo\imNew\chatroom\src\js\link.js和room.js外面,大家能够参考API文档自行补充更多功能 总结以上就是网易云信聊天室解决方案 Demo Web 端接入流程的具体讲解,依照如上步骤就能够轻松实现聊天室的搭建。 任何零碎的搭建都不是欲速不达的,尤其是对于娱乐社交产品而言,自研搭建聊天室意味着较高的人力老本、工夫老本和资金老本。而交融通信云服务专家网易云信所提供的聊天室解决方案,可实现疾速上线,1天即可实现集成工作,轻松应答亿级日活的高并发场景。网易云信也会持续打磨底层技术能力、为开发者提供更多简略集成,疾速接入的音视频和即时通讯解决方案。

August 17, 2021 · 1 min · jiezi

关于c++:驱动开发通过windbg工具进行双机调试的配置

主计算机操作系统:win10虚拟机操作系统:win10 一.创立虚拟机参考:Windows 10 上的 Hyper-V 二.创立虚构网络参考:创立虚构替换网络本次采纳形式一:应用 Hyper-V 管理器创立虚构交换机 关上 Hyper-V 管理器。 执行此操作疾速的办法是按 Windows 按钮或密钥,而后键入“Hyper-V 管理器”。在左窗格中抉择服务器,或在右窗格中单击“连贯到服务器…”。在 Hyper-V 管理器中,从右侧的“操作”菜单中选择虚构交换机管理器... 。在“虚构交换机”局部下,抉择“新建虚构网络交换机”。在“你要创立哪种类型的虚构交换机?”下,抉择“内部”。抉择“创立虚构交换机” 按钮。在“虚构交换机属性”下,为新交换机命名,如“内部 VM 交换机”。在“连贯类型”下,确保已抉择“内部网络”。抉择要与新虚构交换机配对的物理网卡。 这是以物理形式连贯到网络的网卡。抉择“利用” 来创立虚构交换机。 此时,你很可能看到以下音讯。 单击“是”持续。抉择“确定” 敞开虚构交换机管理器窗口。三.禁用平安启动关上 Hyper-v 管理器并抉择创立的虚拟机点击设置。抉择 " 平安 设置"。勾销选中 " 启用平安启动 " 复选框。抉择“确定”以保留设置。四.启动虚拟机确保主计算机和虚拟机能够相互ping通如果不通临时敞开防火墙 五.在虚拟机上启用内核模式调试1.在指标计算机上,以管理员身份关上“命令提示符”窗口。 输出此命令以启用调试(注:hostip是主计算机ip)。 bcdedit /debug onbcdedit /dbgsettings net hostip:192.168.102.113 port:50005bcdedit /set testsigning on六.通过windbg工具连贯虚拟机1.关上命令窗口进入到windbg.exe目录而后输出(windbg.exe -k net:port=50005,key=1ndik7jy60dms.zh9m958erplb.1bkbxwiwz3klu.1gx6qh5e4z61k)key为上一步虚拟机返回的key。或者双击windbg.exe关上后点击file抉择kernel Debug.输出port和key也是一样的。 七.重启虚拟机重启虚拟机后会看到窗口会输入日志,等呈现Debuggee is running...阐明曾经连贯好。 下一篇介绍如何通过VisualStudio2019连贯虚拟机进行双机调试。

August 11, 2021 · 1 min · jiezi

关于c++:leetcode字符串相关

leetcode 3. 无反复最长字串题目形容给定一个字符串 s ,请你找出其中不含有反复字符的 最长子串 的长度。 思路用mp记录字符上次呈现的地位,用last记录以后起始地位,遇到反复的字符计算ans,并更新last。留神:这里因为有last限定了字符串的起始地位,因而每次判断时如果mp[s[i]]在last之前,就不必更新。 class Solution {public: int lengthOfLongestSubstring(string s) { vector<int> mp(129, -1); int len = s.length(), ans = 0, last = 0, i = 0; for(int i=0; i<len; ++i) { if(mp[s[i]] != -1 && mp[s[i]] >= last) { ans = max(ans, i-last); last = mp[s[i]] + 1; } mp[s[i]] = i; } ans = max(ans, len-last); return ans; }};leetcode 10. 正则表达式匹配题目形容给你一个字符串 s 和一个字符法则 p,请你来实现一个反对 '.' 和 '*' 的正则表达式匹配。 '.' 匹配任意单个字符'*' 匹配零个或多个后面的那一个元素所谓匹配,是要涵盖 整个 字符串 s的,而不是局部字符串。 ...

August 10, 2021 · 2 min · jiezi

关于c++:C20-四大特性之一Module-特性详解

C++20 最大的个性是什么? 最大的个性是迄今为止没有哪一款编译器齐全实现了所有个性。 有人认为 C++20 是 C++11 以来最大的一次改变,甚至比 C++11 还要大。本文仅介绍 C++20 四大个性当中的 Module 局部,分为三局部: 探索 C++ 编译链接模型的由来以及利弊介绍 C++20 Module 机制的应用姿态总结 Module 背地的机制、利弊、以及各大编译器的反对状况C++ 是兼容 C 的,岂但兼容了 C 的语法,也兼容了 C 的编译链接模型。1973年初,C 语言根本定型:有了预处理、反对构造体;编译模型也根本定型为:预处理、编译、汇编、链接四个步骤并沿用至今;1973年,K&R 二人应用 C 语言重写了 Unix 内核。 为何要有预处理?为何要有头文件?在 C 诞生的年代,用来跑 C 编译器的计算机 PDP-11 的硬件配置是这样的:内存:64 KiB 硬盘:512 KiB。编译器无奈把较大的源码文件放入狭小的内存,故过后 C 编译器的设计指标是可能反对模块化编译,行将源码分成多个源码文件、挨个编译,以生成多个指标文件,最初整合(链接)成一个可执行文件。 C 编译器别离编译多个源码文件的过程,实际上是一个 One pass compile 的过程,即:从头到尾扫描一遍源码、边扫描边生成指标文件、过眼即忘(以源码文件为单位)、前面的代码不会影响编译器后面的决策,该个性导致了 C 语言的以下特色: 构造体必须先定义再应用,否则无奈晓得成员的类型以及偏移,就无奈生成指标代码。局部变量先定义再应用,否则无奈晓得变量的类型以及在栈中的地位,且为了不便编译器治理栈空间,局部变量必须定义在语句块的开始处。内部变量只须要晓得类型、名字(二者合起来便是申明)即可应用(生成指标代码),内部变量的理论地址由连接器填写。内部函数只需晓得函数名、返回值、参数类型列表(函数申明)即可生成调用函数的指标代码,函数的理论地址由连接器填写。头文件和预处理恰好满足了上述要求,头文件只需用大量的代码,申明好函数原型、构造体等信息,编译时将头文件开展到实现文件中,编译器即可完满执行 One pass comlile 过程了。 至此,咱们看到的都是头文件的必要性和好处,当然,头文件也有很多负面影响: 低效:头文件的本职工作是提供前置申明,而提供前置申明的形式采纳了文本拷贝,文本拷贝过程不带有语法分析,会一股脑将须要的、不须要的申明全副拷贝到源文件中。传递性:最底层的头文件中宏、变量等实体的可见性,能够通过两头头文件“透传”给最上层的头文件,这种透传会带来很多麻烦。升高编译速度:退出 a.h 被三个模块蕴含,则 a 会被开展三次、编译三次。程序相干:程序的行为受头文件的蕴含顺影响,也受是否蕴含某一个头文件影响,在 C++ 中尤为重大(重载)。不确定性:同一个头文件在不同的源文件中可能体现出不同的行为,导致这些不同的起因,可能源自源文件(比方该源文件蕴含的其余头文件、该源文件中定义的宏等),也可能源自编译选项。C++20 中退出了 Module,咱们先看 Module 的根本应用姿态,最初再总结 Module 比 头文件的劣势。 ...

August 9, 2021 · 3 min · jiezi

关于c++:FPNN-112-Release

FPNN 1.1.2 已于7月26日下午正式公布。 比照 0.9.3 版本,次要的改变如下: FPNN UDP 模块正式公开FPNN UDP 提供牢靠UDP链接,开发者可应用UDP牢靠连贯在弱网环境下作为 TCP 链接的代替FPNN DUP 牢靠连贯反对在同一链接中混合发送牢靠数据和非牢靠数据TCP减少更加及时的保活性能,以及更加及时的链接活性检测MultipleURLEngine 接口全面更新,能够在调用接口时间接指定 HTTP 头数据,不必再做独立的内部保护全面反对 GCC/G++ 8 & GCC/G++ 9减少对 CentOS 8 和 Ubuntu Server 20 的反对全面改良文档,重写应用向导,并减少 API 接口文档FPNN 1.0.0 和 1.1.0 两个版本,因为过后文档暂未更新实现,所以没有对外公布。此次1.1.2版本公布,对应文档曾经全副实现更新。后续 云上曲率 RTM 及相干业务将逐渐从1.1.1版本更新至1.1.2版本。 其余开发语言的SDK,将随后陆续更新,并进新公布。 最初,1.1.0版本及1.1.2版本相干性能数据摘要如下: 数据摘要索引 压力测试 TCP 同一局域网TCP 洲际传输:德国法兰克福到美国西部俄勒冈(直线间隔超过8,000公里)UDP 同一局域网UDP 洲际传输:德国法兰克福到美国西部俄勒冈(直线间隔超过8,000公里)海量链接 TCP 同一局域网UDP 同一局域网TCP & UDP 比照测试 新加坡到德国法兰克福(直线间隔超过10,000公里)压力测试 TCP 同一局域网 机型虚构 CPU内存(GB)链接数量QPS均匀响应工夫(usec)AWS m5.xlarge416100049,708335AWS m5.xlarge416130227,91912,854AWS m5.xlarge4161,500148,95910,403AWS m5.xlarge4162,00099,552356AWS m5.xlarge4163,000149,61527,456TCP 洲际传输:德国法兰克福到美国西部俄勒冈(直线间隔超过8,000公里) 机型虚构 CPU内存(GB)链接数量QPS均匀响应工夫(usec)ping/2 (msec)AWS m5.xlarge4161017,921147,825137AWS m5.xlarge416190338,601151,772139AWS m5.xlarge416700339,240183,541136 ~ 137AWS m5.xlarge4163,200312,073256,980139 ~ 141AWS m5.xlarge4166,000299,175346,927136 ~ 137UDP 同一局域网 ...

August 4, 2021 · 1 min · jiezi

关于c++:mongoose

mongoose的源码地址:https://github.com/cesanta/mo... mongoose的用户手册:https://www.cesanta.com/devel...

July 29, 2021 · 1 min · jiezi

关于c++:C-C-入门教程九通讯录管理系统

9 通讯录管理系统咱们要用之前学的所有常识做一个通讯录管理系统。须要实现上面几个性能: 增加通讯录显示通讯录删除通讯录查找通讯录批改通讯录清空通讯录退出通讯录我决定分两层来写,一层 Manager 用来治理和主界面交互的性能,另一层 AddressBook 用来管制底层的存储逻辑。 底层的头文件和源文件如下: //AddressBook.h#pragma once#include<iostream>#include<string>#define MAX 1000using namespace std;struct Node { string name; bool gender; int year; string phone; string address;};struct Book { Node nodes[MAX]{}; int size = 0;};void addBook(Book&, string, bool, int, string, string);void delByNum(Book&, int);void getBook(const Book&);void findBookByName(const Book&, string);void setBookByName(Book&, string, bool, int, string, string);void delAll(Book&);这个头文件定义了一个 node 构造,负责存储每一个具体的人的信息。又定义了一个 Book 构造,存储了一个 node 数组用来存储整个通讯录,并且存储了一个 size 变量用于存储通讯录中有多少集体的信息。并且咱们定义了减少、删除、显示、查找、设置、清空这六项性能。 咱们在源文件中实现了这些性能: //AddressBook.cpp#include"AddressBook.h"void addBook(Book& book, string name, bool gender, int year, string phone, string address) { book.nodes[book.size] = { name,gender,year,phone,address }; book.size++;}void delByNum(Book& book, int num) { for (int i = num - 1; i < book.size - 1; i++) { book.nodes[i] = book.nodes[i + 1]; } book.size--;}void getBook(const Book& book) { for (int i = 0; i < book.size; i++) { cout << '|' << i + 1 << '\t'; cout << '|' << book.nodes[i].name << '\t' << '|'; if (book.nodes[i].gender) { cout << "Male"; } else { cout << "Female"; } cout << '\t' << '|' << book.nodes[i].year << '\t' << '|' << book.nodes[i].phone << '\t' << '|' << book.nodes[i].address << '\t' << '|' << endl; }}void findBookByName(const Book& book, string name) { for (int i = 0; i < book.size; i++) { if (book.nodes[i].name == name) { cout << '|' << i + 1 << '\t'; cout << '|' << book.nodes[i].name << '\t' << '|'; if (book.nodes[i].gender) { cout << "Male"; } else { cout << "Female"; } cout << '\t' << '|' << book.nodes[i].year << '\t' << '|' << book.nodes[i].phone << '\t' << '|' << book.nodes[i].address << '\t' << '|' << endl; goto FLAG; } } cout << "no founding." << endl;FLAG: cout << endl;}void setBookByName(Book& book, string name, bool gender, int year, string phone, string address) { for (int i = 0; i < book.size; i++) { if (book.nodes[i].name == name) { book.nodes[i].gender = gender; book.nodes[i].year = year; book.nodes[i].phone = phone; book.nodes[i].address = address; goto FLAG; } } cout << "no founding." << endl;FLAG: cout << endl;}void delAll(Book& book) { book.size = 0;}然而这些性能只是负责底层交互的,然而这些函数都须要很多的参数,调用的时候如果还要写很多的语句来补充参数代码看起来就很简单。所以咱们须要再封装一层,把取得参数的这些语句也封装起来。 ...

July 22, 2021 · 4 min · jiezi

关于c++:C-C-入门教程八结构体

8 构造体8.1 构造体基本概念构造体属于用户自定义的数据类型,容许用户存储不同的数据类型 8.2 构造体定义和应用定义语法:struct structureName{ memberList }; 创立语法: struct StructureName variableName;struct StructureName variableName{ member1, member2…… };定义时创立struct StructureName{ memberList }variableName;通过语法veriable.member来拜访构造成员 8.3 构造体数组作用:将自定义的构造体放入数组中保护 语法:StructureName variableName[ dataNum ]{{},{}……}; 8.4 构造体指针作用:通过指针拜访构造体中的成员 利用操作符->来通过指针拜访构造体的属性 8.5 构造体作为参数构造体也是分为传值和传址的。和数组不同,数组自身就能够作为一个指针,然而构造体不行,构造体自身是一种变量,所以必须应用传址的办法能力扭转构造自身。 留神:这一点和 Python, Java 都不一样,须要独自记忆一下。 8.6 构造体中 const 实用场景传值尽管好用(哪里好用?)然而每一次传值,形参到实参都必须复制一次,十分占用资源。而如果咱们传址的话,就只须要四个字节,能够缩小对内存数据的占用。 然而指针拜访数据会有隐患,在函数中就能批改数值了。 因而,咱们为了爱护实参的内容,不容许扭转,因而咱们应用常量指针const structName* variableName作为参数传入。

July 22, 2021 · 1 min · jiezi

关于c++:C-C-入门教程七指针

7 指针7.1 指针的基本概念作用:通过指针间接拜访内存 内存编号是从0开始的,个别是十六进制示意的(具体几个字节应该是看零碎的)能够利用指针变量来存变量的地址7.2 指针变量的定义和应用语法:dataType * pointVariableName = &variableName &是一个取地址符号。 你能够用解援用符号*来拜访指针拜访的内存。 *pointVariableName就示意variableName这一块内存里的存储的变量 7.3 指针所占内存空间指针也是一种数据类型,那么这种类型占多少空间呢? 猜想,和零碎相干。64位的零碎的内存地址可能是64位,而32位零碎可能是32位。在32位零碎下占用4个字节。而64位零碎占8个字节。然而大多数开发环境都是32位。(此处也能够抉择x64编译环境来切换。 7.4 空指针和野指针空指针:指针变量指向内存中编号为 0 的空间 用处:初始化 留神:空指针指向的内存是不能拜访的 语法:dataType* pointVariableName = NULL; 野指针:指针指向了非法的内存空间 这是一种谬误,在程序中要尽量避免呈现野指针 语法:int* p = (int*) 0x1100; 然而实际上 0x1100 这块空间是没有申请的。这块空间上没有申明任何的变量,也就没有被零碎调配一块内存。因而是没有权限拜访的。这样的程序是有谬误的。 7.5 const 润饰指针const 润饰指针有三种状况: const 润饰指针:常量指针const dataType* pointVariableName 指针自身能够扭转,然而指针指向的值不能通过指针扭转。 const 润饰变量:指针常量dataType* const pointVariableName 指针自身不能够改,然而指针指向的值可扭转。 const 即润饰指针又润饰变量 用两个 const 就能够了const dataType* const pointVariableName7.6 传址指针能够作为参数传入函数。这种过程咱们成为址传递,又称为传址。传址后就能够批改实参具体的值。 如果抉择将数组作为参数传入函数,有两种传法,一个是int arr[],而数组能够看做是一个指针,因而也能够抉择用int* arr的办法传入,这样他就作为一个指针传入了。

July 22, 2021 · 1 min · jiezi

关于c++:C-C-入门教程六-函数

6 函数6.1 概述作用:将一段常常应用的代码封装起来,缩小重置的代码 一个较大的程序,个别能够分为很多的程序块,每个模块都能够封装起来作为一个函数性能。 6.2 函数的定义定义函数: 返回值类型函数名参数列表函数体return 表达式6.3 函数的调用语法:functionName( peremeterList ) 函数中的参数,咱们成为形式参数,简称形参。 而咱们调用参数的时候传入的参数为理论参数,简称实参。 调用函数的时候,实参的值会传递给形参,这种值传递也成为传值。 6.4 值传递函数调用时,会将实参的值传入函数的形参,这个过程称为值传递,又称为传值。 因而,传值时,如果形参产生扭转,不会影响实参自身的值。只有传址或者传援用能够扭转实参的值。 6.5 函数的申明作用:通知编译器函数名称以及如何调用函数,函数的理论主体能够在前面独自定义。 函数能够申明很屡次,然而只能定义一次。 函数申明自身对于开发者的意义更多是提前就能晓得这个程序中的局部函数是怎么运行的,而后能够间接去看主函数。而对于编译器来说,理论就相当于把函数的定义间接写在了申明的中央了。编译器发现函数申明之后,就会间接去寻找绝对应的函数定义,并且把函数编译进来。 不过函数申明有一个长处。当函数须要调用另一个函数的时候,函数的定义是有先后的。必须要先定义被调用的函数,再定义调用函数的函数。然而如果在文件头一起申明的话,就不会有这个问题了。而且申明是不须要留神程序的。 6.6 函数的分文件编写作用:让函数构造更加清晰 步骤: 创立后缀名为.h的头文件创立后缀名为.cpp的源文件在头文件中写函数的申明在源文件中写函数的定义做一个简略的替换两个数的函数,把函数独自放在程序中。 先写函数自身的源文件 //swap.cpp#include"swap.h"void swap(int& a, int& b) { int space; space = a; a = b; b = space;}而后写这个函数的申明,放在一个头文件中 #pragma oncevoid swap(int&, int&);其中#pragma once作用和上面的代码差不多: #ifndef A_H#define A_H……#endifpragma 是编译附注,这句话示意这个头文件只能被编译一次。整个编译过程中只能关上文件一次。 拓展: 办法一:pragma once 办法二:ifndef A_H 这两个办法没有太大的区别。细节上说,办法二的可移植性更高,有些编译器不反对办法一。另一方面,办法一是物理层面上一个文件不会被编译两次。然而如果一个文件有多份拷贝,就会都关上。 而办法二重视的则是文件名。只有文件一样,多少拷贝都只会编译一次。然而如果多个头文件是一个名字的话,也有可能导致剩下的几个不被编译了。 最初咱们编写主函数: //main.cpp#include<iostream>#include"swap.h"using namespace std;int main() { int a = 10, b = 20; cout << "替换前:" << endl; cout << "a = " << a << endl; cout << "b = " << b << endl; swap(a, b); cout << "替换后:" << endl; cout << "a = " << a << endl; cout << "b = " << b << endl;}留神一下:本人编写的头文件蕴含用双引号"",而零碎提供的头文件则用尖括号<>。 ...

July 21, 2021 · 1 min · jiezi

关于c++:C-C入门教程五-数组

5 数组5.1 概述所谓数组,就是一个汇合,外面寄存了雷同类型的数据元素 特点1:同一个类型 特点2:存储空间间断 5.2 一位数组5.2.1 一位数组的定义形式三种定义形式: 数据类型 数组名[ 数组长度 ];数据类型 数组名[ 数组长度 ] = { 值1, 值2,……};数据类型 数组名[] = { 值1, 值2,……};第三种定义方法并不是没有数组长度,而是编译器会依据你前面的值的数量主动生成一个长度。 5.2.2 数组名的用处能够统计数组在内存中的长度 能够获取数组在内存中的首地址 思考: 我当初有一个数组int arr[10]此时,arr代表的是第一个元素的地址 那么,arr+1 应该和 &arr[1] 一样,代表的是第二个元素的地址 如果是 &arr[0] + 1呢,代表的是第一个元素的第二个字节的地址么? 对于数组名的几种应用,对于数组名的意义,我做了一个试验,写了代码如下: #include<iostream>using namespace std;int main() { int arr[7]{ 5,2,0,1,3,1,4 }; cout << "&arr[0] = " << (int)&arr[0] << endl; cout << "arr = " << (int)arr << endl; cout << "&arr[1] = " << (int)&arr[1] << endl; cout << "arr + 1 = " << (int)(arr + 1) << endl; cout << "&arr[0] +1 = " << (int)(&arr[0] + 1) << endl; cout << "&arr + 1 = " << (int)(&arr + 1) << endl; cin.get(); return 0;}别离对应几种组合,最初输入如下: ...

July 20, 2021 · 1 min · jiezi

关于c++:C-C入门教程四-程序流程结构

4 程序流程构造C++反对最根本的三种程序运行构造: 程序构造抉择构造循环构造4.1 抉择构造4.1.1 if 语句作用:执行满足条件的语句 if 语句能够嵌套叠加 单行格局 if 语句if(条件){条件满足需要执行的语句;} 多行格局 if 语句if(条件){条件满足执行的语句}else{条件不满足执行的语句} 多条件 if 语句if(条件){满足的语句}else if(条件2){满足条件1但不满足条件2的语句}…else{都不满足的语句};练习案例 有三只小猪ABC,请别离输出三只小猪的体重,并判断谁最重。 #include<iostream>#include<string>using namespace std;class Pig { string name; int weight;public: Pig() { cout << "Pig constructed." << endl; } ~Pig() { cout << "Pig disconstructed." << endl; } void setName(string n) { name = n; } void setWeight(int w) { weight = w; } int getWeight() { return weight; } string getName() { return name; }};int main() { string name; int weight; Pig pigA; cout << "Please enter the name of pig A: "; cin >> name; pigA.setName(name); cout << "Please enter the weight of pig A: "; cin >> weight; pigA.setWeight(weight); Pig pigB; cout << "Please enter the name of pig B: "; cin >> name; pigB.setName(name); cout << "Please enter the weight of pig B: "; cin >> weight; pigB.setWeight(weight); Pig pigC; cout << "Please enter the name of pig C: "; cin >> name; pigC.setName(name); cout << "Please enter the weight of pig C: "; cin >> weight; pigC.setWeight(weight); if (pigA.getWeight() >= pigB.getWeight() && pigA.getWeight() >= pigC.getWeight()){ cout << pigA.getName() << " is the heavieat." << endl; } else if (pigB.getWeight() >= pigA.getWeight() && pigB.getWeight() >= pigC.getWeight()){ cout << pigB.getName() << " is the heavieat." << endl; } else{ cout << pigC.getName() << " is the heavieat." << endl; } cin.get(); return 0;}我在构造函数和解析函数中增加了输入语句。因而能够看出,如果不必new和delete的话,编译器也会主动地开释空间。 ...

July 20, 2021 · 2 min · jiezi

关于c++:C-入门教程三-运算符

3 运算符作用:用于执行代码的运算 3.1 算术运算符作用:用于解决加减乘除 + - * / 加减乘除 / 除法:两个整数相除的时候,后果仍然是整数,小数局部将会被去除 % 取模(又称取余):只能是两个整数取余 ++ 递增 --递加:让变量自加1,或自减1 前置递增(递加):递增(递加)运算符放变量后面,会先增后算。相同则会先算后增。 int main(){ using namespace std; //前置运算,最初会失去a=3, b=3 int a=2; int b=++a; cout<<b<<endl; //后置运算,最初会失去a=3, b=2 int c=2; int d=c++; cout<<d<<endl; return 0;}3.2 赋值运算符作用:把左边的值赋给右边 = 赋值运算 +=, -=, *=, /= 加等于,建等于,乘等于,除等于:这些符号一种简化,示意将右边对右做运算后将后果赋给右边。 3.3 比拟运算符作用:用于表达式的比拟,并返回一个布尔值。 == 等于 != 不等于 < 小于 \> 大于 <= 小于等于 \>= 大于等于 3.4 逻辑运算符作用:对值进行逻辑解决 ! 逻辑非运算 && 逻辑与运算 || 逻辑或运算 3.5 操作符优先级小结(补充)3.5.1 优先级1(优先级由高到低)从左到右联合最高优先级:括号 () 所有优先级都能够被括号突破 ...

July 20, 2021 · 1 min · jiezi

关于c++:C-C-入门教程二基本数据类型

2 数据类型2.1 整型C++ 中可能示意整型的类型有大略四种,区别在于所占空间的不同: 数据类型占用空间(单位:字节)short2int4longWindows(4), Linux(4), 64位零碎(8)long long8尽管我的零碎是64位的,然而试验了一下,可能是因为 VS 的起因,导致我写进去的 long 类型只有 4 个字节。这个其实不是特地的稳固,所以之后还是尽量少用 long 类型。 2.2 sizeof 关键字作用:能够统计一个数据类型占用的空间大小。 语法:sizeof(数据类型/变量) 单位:字节 依据之前的试验,sizeof 关键字不仅能够统计根本数据类型所占的空间大小,构造体、类都是能够通过 sizeof 来进行断定的。至于对于类中的动态对象、办法等占用空间是怎么计算的。能够先留一下,之后再看。2.3 浮点型浮点型变量分为两种:float, double 数据类型占用空间(单位:字节)有效数字范畴float47位double815-16位默认状况下,编译器会把一个小数当成一个双精度浮点数 double 类型,咱们在创立一个单精度变量的时候,能够通过加 'f' 后缀来间接失去一个单精度的常数。 默认状况下,输入一个小数,会显示六位有效数字。 示意小数的两种形式: 小数点计数法:即应用小数点来示意,相似于3.14159之类的。迷信计数法:相似于3e2,通过 e 来宰割。e 的后面是有效数字,前面是2.4 字符型作用:显示单个的字符。 我的了解是,尽管 char 类型中存储的数据实质是 ASCII 码,然而在进行输入的时候,一旦计算机辨认进去这个数据是 char 类型,则会把他当成字符自身进行输入。所以 char 自身是能够像个别的数据一样加减的。语法:char ch = 'a'; 有两点留神:一是字符须要用单引号 '' 扩起来,二则是单引号中只能放进一个字符。 通过强制转换,能够输出 ASCII 码,或者输入 ASCII 码。 输入 ASCII 码能够将须要输入 ASCII 码的字符转换为整型,而后输入。 int main() { char ch = 'A'; cout << (int)ch << endl; return 0;}输出 ASCII 码ASCII 码是能够间接输入的,像这样: ...

July 20, 2021 · 1 min · jiezi

关于c++:C-入门教程一-C初识

1 C++ 初识1.1 第一个 C++ 程序1.2 正文单行正文:// 多行正文:/**/ 1.3 变量变量存在的意义:不便咱们治理内存空间 每一块内存都有一个十六位的地址码 然而如果咱们用了变量的名字,咱们就能够不必地址码就能间接能调用这个数据了。 变量创立的办法: 数据类型 变量名称 = 变量的初始值;1.4 常量用来记录不能够批改的数据。 C++ 定义常量有两种办法: 1、#define 宏常量 #define 常量名 常量值通常在文件上方定义,用来示意一个常量。 2、const 润饰变量 const 数据类型 变量名称 = 常量值在变量的定义前增加const,则这个数据不能够被批改。 1.5 关键字在定义常量或变量时,不能够用关键字的名字,不然会产生歧义。 1.6 标识符命名规定不能够是关键字由字母、数字、下划线形成数字不能够是第一个字符标识符明明辨别大小写给变量取名字的时候尽量做到见量知意。

July 20, 2021 · 1 min · jiezi

关于c++:关于持久内存你了解多少

你说不定在不同的渠道曾经据说过一些相似的让人一头雾水的技术名词,比方非易失性存储,长久内存,傲腾长久内存,甚至英文的名词 Optane SSD, Optane persistent memory, PMem, DCPMM, AEP 等等…… 这些名词到底是什么?有什么分割?有什么用途?本文从科普的角度,帮你答复这些问题。心愿你看了本文当前,不论你是程序员还是相干行业从业者,至多都能明确什么是长久内存,它到底能施展什么样的作用。 长久内存到底是什么?首先答复一下凌乱的命名问题,咱们临时不纠结于这些名字之间的演变关系了,简略来说能够认为大部分都是指的同一个货色(当然不是严格正确)。目前Intel中文官网命名为“英特尔傲腾长久内存”,简称为“长久内存”。英文官网名为 Intel Optane Persistent Memory,简称为 PMem。因而在本篇文章中,对立应用“长久内存”或者“PMem”进行指代。那么正式开始……说到底,长久内存其实是一种新型的内存条,咱们能够先来看一下,它长这个样子,和一般内存条其实没啥特地大差别,而且它就是插在服务器的内存插槽里的。所以简略来说,你能够自行购买,而后插到你的服务器上的内存插槽上,你就能够应用长久内存啦。当然,长久内存对于硬件是有肯定的要求的,AMD的CPU就不必想了,长久内存属于 Intel 的独家法宝,天然不会留给竞争对手做反对。具体CPU的反对型号能够自行查找,这里不多赘述。当然如果想要施展长久内存的最大劣势,其在硬件配置插法上是有肯定的考究的,前面将会具体开展。而后咱们钻研下长久内存在整个计算机体系架构中的地位。学过计算机的同学,肯定对计算机的存储金字塔的架构十分相熟,那么如果咱们把长久内存也放到这个金字塔里,会是在什么地位呢?咱们具体来看一下。如下图所示的存储金字塔中,咱们能够看到长久内存处于外存(HDD或者SSD)以及内存DRAM之间,其不管在容量、性能、价格上都是处于两者的两头地位。除此以外,在性能上,它齐全就是个DRAM和外存的混血儿(所以为什么在图上PMEM标记为一半是淡水,个别是火焰)。也就是说,它即能够当做内存应用,也能够当做长久化外存设施应用,当然也能够两者兼顾,齐全取决于你如何应用长久内存。如果你还是不太能了解我形容的是什么,那么最间接的,通知你长久内存三个最重要的特色:大, 快,持久性: 大:目前长久内存单条内存容量最大能够达到 512 GB,而目前服务器单条内存个别最多到 32/64 GB。也就是说,单台服务器应用长久内存能够轻松达到 TB 级别的内存容量。另一方面,单位价格来说,长久内存为一般内存的一半左右。快:既然也号称为内存,那必然不能慢。能够看到,长久内存相比拟于一般 SSD 有1-2个数量级的提早性能劣势,相比拟于硬盘劣势更加微小。当然比照与DRAM,其会有肯定的性能差距。然而理论应用中因为性能瓶颈不肯定在内存上,所以个别不会有特地显著的差距(个别性能消退在一倍以内)。持久性:艰深来说,就是长久内存有跟硬盘一样的个性,断电当前重启,内存中的数据仍然存在。此项个性能够说是秒杀内存,内存中的数据咱们都晓得断电或者程序以外退出当前就不复存在。此项个性使得长久内存即能够当做一个高速长久化设施应用,也能够满足内存利用某些场景下的疾速复原的需要。如下表格总结了对于数据中心单台服务器上的典型配置,以及相应的大抵的性能数字作为参考。 常见内存和长久化设施在单台服务器上的大抵性能体现长久内存次要劣势场景是什么?说完了长久内存的个性,大家肯定也能设想出它在某些利用场景下具备得天独厚的劣势。具体来说,长久内存在理论落地中可能有以下几种玩法。以下从几个具体场景举例登程,并且辩证的给出应用长久内存带来的劣势,以及可能引入的问题。场景1:大内存低成本解决方案如果你的利用内存消耗量是要害,是整个零碎的资源瓶颈,那么应用长久内存将会是你降低成本的最佳解决方案。你的零碎个别在两种状况下对于大内存有特地的需要基于内存性能的考量,你必须应用基于内存的解决方案,而不可能应用基于磁盘的计划,比方内存数据库(Redis, MemSQL)。尽管你的利用能够承受基于磁盘而带来的性能损耗,然而显然如果内存扩充,你的利用能够跑得更快更加节省时间,比方基于 Spark 搭建的利用。此种场景下,你能够思考应用长久内存来提供一个大内存低成本的解决方案。劣势:长久内存在单位价格上约为一般内存的一半,并且能够在单台机器上轻松达到 1.5 TB,甚至 3 TB 的内存大小。因而比方你指标须要 20 TB 的总内存容量,长久内存可能只须要10台机器即可满足,然而基于DDR内存的集群可能须要40台甚至更多。思考机器投入以及经营上带来的老本,长久内存所带来的低成本解决方案的劣势是不言而喻的。可能的问题:当然引入长久内存,相比拟于内存可能会带来肯定的性能消退,消退的起因可能是长久内存自身所引起的,也可能是因为机器台数缩小,其余硬件资源(比方CPU核数或者网络带宽)缩小所引起的。所以理论我的项目落地中,作为决策者,肯定须要进行审慎评估,来量化长久内存带来的利害关系。场景2:高性能长久化需要的利用长久内存作为一个内存和外存的混合体,其高速长久化的个性在某些磁盘 IO 作为性能瓶颈的场景下是一个破局的解法。尽管 SSD 肯定水平上也能够缓解磁盘 IO 性能瓶颈,然而相比拟于 PMem 这种能够实现两个数量级的吞吐和提早改良的长久化设施来说,PMem 无疑是具备革命性的意义的。以下抛砖引玉举几个磁盘IO作为性能瓶颈的场景。音讯队列:大家相熟的开源音讯队列 Kafka,因为其音讯长久化逻辑的存在,其吞吐最终会卡在硬盘 IO 上。目前的解法是一直堆机器来扩大整个 Kafka 集群的吞吐。搜寻零碎:相似于 Kafka,风行的开源搜寻零碎 Elasticsearch,也将局部的数据结构寄存在磁盘上。那么最终影响整体提早和吞吐的将会是磁盘 IO 的性能。数据库或者KV存储引擎:比方 MySQL 或者 RocksDB,都具备重要的面向外存的数据长久化逻辑。分布式文件系统:在人工智能场景中,经常会有大量的小文件存在。比方在 Ceph 的文件系统中,在 metadata server 上对大量小文件的治理经常因为大量随机读写的存在而产生性能问题。劣势:显然,对于有高速长久化读写需要的场景,长久内存引入间接有了数量级的性能晋升。在吞吐方面,因为单机吞吐晋升,因而总的机器数量规模能够大量缩小,在提早方面则是提供了另一给维度的劣势。具体性能比对能够参照上一节开端给出的性能比对表格。可能的问题:PMem 作为纯正的长久化设施可能是把双刃剑,最次要的问题是其容量相比拟于传统硬盘来说还是偏小,同时单位成本也高。因而对于某些场景下如果除了对于性能,对于容量也有较高的要求,那么应用 PMem 带来性能的晋升,然而也可能会造成老本的回升。场景3:内存数据持久性的利用这种场景下,实质上还是把 PMem 当做一个内存来应用,和上一个高性能长久化的场景有所类似有所区别。上一个场景次要是针对原本软件架构设计就有长久化逻辑(比方文件系统原本就须要存在硬盘上),而后咱们把长久化逻辑搬移到PMem上就能够。其自身可能并不波及到简单的数据结构的批改,因为其原本的设计就曾经带有了长久化逻辑。然而在场景 3 这种内存数据长久化场景中,软件自身的内存数据结构的设计是没有思考到长久化逻辑的。因而你须要针对内存中的数据结构从新设计长久化数据结构和逻辑。这一类利用对开发的要求是最高的,同时也是最能齐全施展 PMem 的特点。此种场景往往是原本就是基于纯内存的利用,然而心愿减少数据长久的个性,最常见的需要是因为要疾速数据恢复。此种需要个别来自线上服务零碎(比方数据库 Redis,或者人工智能场景下的参数服务器、特色工程数据库等),线上服务一旦节点离线,都会造成服务质量的影响。因为零碎是基于内存数据结构,离线当前的数据恢复往往须要小时级别的工夫来从新抓取数据,并且从新构建内存中的数据结构。如果有了长久内存,此类服务不仅可能通过大内存降低成本,而且能够减少疾速复原性能,保障线上服务质量。劣势:如上所述,此种模式下,能够把长久内存的劣势充分发挥进去。首先大内存带来硬件老本的降落,其次,通过持久性,赋予了原本的内存利用的新的长久化个性,能够反对数据疾速回复,保障线上服务质量。可能的问题:此种利用惟一的问题可能是带来比拟多的额定的开发工作量。个别的内存数据结构都没有长久化逻辑,个别要求程序员通过 PMDK 从新设计长久化数据结构和逻辑,实现冀望中的内存数据长久化。如何做做长久内存的开发?首先必须弄明确,如果memory mode这种低成本扩大内存容量的形式能够满足你的业务需要,那么你基本不须要开发成本。然而如果不能满足你的需要,存在以下几种问题,那么你可能得动脑子想想须要如何对现有场景进行革新。• 内存模式性能消退过于显著,心愿应用大容量内存的同时,放弃和DRAM靠近的性能• 想利用长久内存来代替(或者一部分代替)传统外存设施,利用其高速长久化个性• 心愿对内存数据做长久化,提供离线当前的疾速复原性能长久内存的开发会是一个十分大的topic,而且依据你想要达到的目标不同,思路会齐全不一样,咱们这里不做开展。较量邀请基于以上介绍,置信你曾经对长久内存有了初步的理解。那么你想理解更多吗?你想切身感受这项技术吗?如果你想体验长久内存在AI利用上进一步的摸索的话,咱们为你提供了良好的机会!第四范式联结英特尔独特举办了【AI利用与异构内存编程挑战赛】,此次较量基于人工智能利用,以异构内存架构为硬件底座,基于英特尔® 傲腾™ 长久内存的前沿利用摸索及硬核编程挑战赛。通过较量你将会对人工智能如何在异构内存架构上受害有全新的意识,步入技术新境界。大赛会有技术专家亲自领导及解说。同时还设有高达20万元的赛道处分,以及为高校学生提供了Intel&第四范式联结实验室实习机会。欢送所有技术背景或对此项技术感兴趣的人群报名。高处分、双赛道、低门槛、良好的体验环境及技术支持,还不赶快报名!大赛官网:https://opensource.4paradigm....报名注册链接:http://openaios.4paradigm.com ...

July 16, 2021 · 1 min · jiezi

关于c++:招募ACM世界冠军ACM杰出科学家强烈推荐第四范式x英特尔AI应用与异构内存编程挑战赛

2021年7月8日,由第四范式与英特尔独特主办的“AI利用与异构内存编程挑战赛”正式开赛!大赛基于人工智能利用、英特尔® 傲腾™ 长久内存,以异构内存架构为硬件底座,进行两者联合的前沿利用摸索及硬核编程挑战赛。大赛失去了ACM世界冠军、ACM年度卓越科学家、Intel首席长久内存架构师的统一举荐与认可。欢送宽广IT 行业开发人员,高校计算机相关业余同学,及对异构内存感兴趣的人群参赛。 【大赛主席团寄语】“这是咱们首次举办基于第四范式开源技术组件的AI开发者大赛。通过较量能够让选手们体验到工业界最先进的技术,将技术境界拓展到新的维度和高度。”——大赛主席【郑曌】、第四范式技术副总裁,根底技术研发负责人(郑曌,2010年ACM世界总冠军,曾在硅谷工作多年、先后就任于 Google 展现广告架构团队,Pinterest 搜寻团队并负责 Pinterest 搜寻架构与 个性化团队负责人,领有丰盛的大规模搜寻架构、个性化举荐架构、机器学习零碎架构教训和技术团队治理教训。) “本次较量使用到了咱们去年在VLDB上发表论文(http://vldb.org/pvldb/vol14/p...)的关键技术点。让选手们切实体验如何利用新兴硬件来进步零碎性能。我强烈建议大家加入此次较量。”——大赛联结主席【Dr. He Bingsheng】,ACM卓越科学家,加坡国立大学计算机学院首席副教授、副校长(Dr. Bingsheng,曾负责数据库、云计算、并行和分布式系统国内会议的评委会成员,并负责VLDB 2017的演示联结主席,IEEE CloudCom 2014/2015的评委会联结主席,2020年被评为ACM卓越科学家,在国内出名会议和期刊上取得多个论文奖和荣誉称号。) “此次较量波及到了英特尔与第四范式在顶级数据库会议上发表的钻研论文以及相干白皮书中(https://www.intel.cn/content/...)的内容。为了帮忙更多的开发者体验先进的内存技术、理解它的价值、学习这种编程模式,我诚挚的邀请大家加入本次较量。”——大赛联结主席【Andy Ruodff】,Intel首席长久内存架构师、非易失性存储编程先驱(Andy Ruodff,英特尔傲腾数据中心及长久内存首席架构师,PMDK PMC核心成员。) 【大赛详情】赛道处分总价值高达20万!低门槛、处分高,欢送前来报名!报名链接:https://openaios.4paradigm.com/官网链接: https://opensource.4paradigm....

July 14, 2021 · 1 min · jiezi

关于c++:LP102-2019

LP102 2019 SpringHomework 1AbstractWrite a C [1] program that can play the games of Go and GoBan.1 Introduction of Go and GobanGo (called WeiQi in China) and Goban (called WuZiQi in China) are ancientboard games. The board is marked by horizontal and vertical lines. Stones,white or black, will be placed on the intersections of lines. Two players willuse different colors of stone, and put their stones in turn on the board. Goand Gomoku have different rules of winning. The rules of the two games aresimple. We can find online documents for their rules.Rules of Go:The picture above is from https://tromp.github.io/go/le...1https://en.wikipedia.org/wiki...https://senseis.xmp.net/?Basi...Rules of Goban:https://en.wikipedia.org/wiki...2 Gaming data storage2.1 Board and stoneA 2–dimentional array of integers is used to record the stones on the board.If the board has 19 × 19 lines, then we can use an 19 × 19 board. At aline interscetion on the board, there are 3 possible stone occurrences there:Empty, Black, White. We can use 3 different integers of represent the 3stones, such as 0, 1, 2. Initially, the board is empty, which means each itemin the 2D arrary of the board is Empty. When a user pick a coordinate, sayE 6, to place a stone, say a black stone, if Black is represented as 1, thenthe corresponding update of the board can be represented as the followingassignment statement:board4 = 12.2 Game play history recordWe can use a 3D integer array to record the history of a game, which isa sequence the positions where stones are put during the game. We don’tneed to remember which position is black or white in the history, since weassume a black stone is always put first. This history array will be saved toa file on a hard drive, or be loaded from a hard drive to memory.3 Display of gaming dataThe board and stones can be printed using ASCII characters at the commandline. Here is some screen record of playing GNU Go:White (O) has captured 0 piecesBlack (X) has captured 0 piecesA B C D E F G H J K L M N O P Q R S T Last move: White C519 . . . . . . . . . . . . . . . . . . . 19218 . . . . . . . . . . . . . . . . . . . 1817 . . . . . . . . . . . . . . . . O . . 1716 . . . + . . . . . + . . . . . O X . . 1615 . . . . . . . . . . . . . . . . O . . 1514 . . . . . . . . . . . . . . . X . . . 1413 . . . . . . . . . . . . . . . . . . . 1312 . . . . . . . . . . . . . . . . . . . 1211 . . . . . . . . . . . . . . . . . . . 1110 . . . + . . . . . + . . . . . X . . . 109 . . . . . . . . . . . . . . . . . . . 98 . . . . . . . . . . . . . . . . . . . 87 . . . . . . . . . . . . . . . . . . . 76 . . . . . . . . . . . . . . . . . . . 65 . .(O). . . . . . . . . . . . . . . . 54 . . . + . . . . . + . . . . . + . . . 43 . . . X . . . . . . . . . . . . . . . 32 . . . . . . . . . . . . . . . . . . . 21 . . . . . . . . . . . . . . . . . . . 1A B C D E F G H J K L M N O P Q R S Tblack(9): o2White (O) has captured 0 piecesBlack (X) has captured 0 piecesA B C D E F G H J K L M N O P Q R S T Last move: Black O219 . . . . . . . . . . . . . . . . . . . 1918 . . . . . . . . . . . . . . . . . . . 1817 . . . . . . . . . . . . . . . . O . . 1716 . . . + . . . . . + . . . . . O X . . 1615 . . . . . . . . . . . . . . . . O . . 1514 . . . . . . . . . . . . . . . X . . . 1413 . . . . . . . . . . . . . . . . . . . 1312 . . . . . . . . . . . . . . . . . . . 1211 . . . . . . . . . . . . . . . . . . . 1110 . . . + . . . . . + . . . . . X . . . 109 . . . . . . . . . . . . . . . . . . . 98 . . . . . . . . . . . . . . . . . . . 87 . . . . . . . . . . . . . . . . . . . 76 . . . . . . . . . . . . . . . . . . . 635 . . O . . . . . . . . . . . . . . . . 54 . . . + . . . . . + . . . . . + . . . 43 . . . X . . . . . . . . . . . . . . . 32 . . . . . . . . . . . . .(X). . . . . 21 . . . . . . . . . . . . . . . . . . . 1A B C D E F G H J K L M N O P Q R S TGNU Go is thinking...white(10): E4Here is the screen shot of playing Goban using with another board design:This the game setting:board-size: 13; win-size: 5; lines-on-board: YesEnter to continue!!!!!!! Welcome to Dragon Go !!!!!!A B C D E F G H J K L M N13 +---+---+---+---+---+---+---+---+---+---+---+---+ 13| | | | | | | | | | | | |12 +---+---+---+---+---+---+---+---+---+---+---+---+ 12| | | | | | | | | | | | |11 +---+---+---+---+---+---+---+---+---+---+---+---+ 11| | | | | | | | | | | | |10 +---+---+---+---+---+---+---+---+---+---+---+---+ 10| | | | | | | | | | | | |9 +---+---+---+---+---+---+---+---+---+---+---+---+ 9| | | | | | | | | | | | |8 +---+---+---+---+---+---+---+---+---+---+---+---+ 8| | | | | | | | | | | | |7 +---+---+---+---+---+---+---+---+---+---+---+---+ 7| | | | | | | | | | | | |6 +---+---+---+---+---+---+---+---+---+---+---+---+ 6| | | | | | | | | | | | |5 +---+---+---+---+---+---+---+---+---+---+---+---+ 5| | | | | | | | | | | | |44 +---+---+---+---+---+---+---+---+---+---+---+---+ 4| | | | | | | | | | | | |3 +---+---+---+---+---+---+---+---+---+---+---+---+ 3| | | | | | | | | | | | |2 +---+---+---+---+---+---+---+---+---+---+---+---+ 2| | | | | | | | | | | | |1 +---+---+---+---+---+---+---+---+---+---+---+---+ 1 ...

July 13, 2021 · 15 min · jiezi

关于c++:PapaMelon-2-AB-注意整形溢出

题目链接A+B题解这道题次要是用于相熟 OJ 的输入输出输出的两个整数范畴都在 int32 范畴内,但相加后可不肯定了 :),留神溢出的问题#include <iostream>using namespace std;int main() { int a, b; while (cin >> a >> b) { cout << 0LL + a + b << endl; } return 0;}

July 12, 2021 · 1 min · jiezi

关于c++:EEE102-软件设计

EEE102 Assessment 31EEE102 C++ Programming and Software Engineering IIAssessment 3Assessment Number 3Contribution to Overall Marks 35%Submission Deadline Wednesday, 01-May-2019, 23:59How the work should be submitted?SOFT COPY ONLY !(MUST be submitted through ICE so that the TAs can run your programs during marking.)Make sure your name and ID are printed on the cover page of your report.Assessment OverviewThis assessment aims at testing some basic concepts of C++ programming and initiates the routine ofcode development using the software development process (SDP), namely the five main steps of thesoftware development process: ...

July 12, 2021 · 4 min · jiezi

关于c++:STLvector内部实现原理及基本用法

1.vector类的实现重要构造定义: template<class T>class myVector{public: typedef T value_type;//元素类型 起别名 typedef value_type* pointer;// typedef value_type* iterator;//迭代器 typedef value_type& reference;//援用 typedef const value_type* const_pointer;//常量指针 typedef const value_type& const_reference;//常量援用 typedef size_t size_type;//数据类型根本尺寸大小private: iterator start; iterator finish; iterator end_of_storage;供类外部以及派生类应用: protected://调配空间并填充初始值, 不返回任何值void __allocate_add_fill(size_type n, const T& value){ iterator result = (iterator)malloc(n*sizeof(T)); if (result){//result!=0 申请内存胜利,在失去的内存上创建对象 start = result; end_of_storage = start + n; finish = end_of_storage; while (n--){ //指针偏移,进行赋值 construct(result, value);//在内存上,一个个的进行结构对象 ++result; } } else{ cout << "内存不足,程序终止!" << endl; exit(0); } }//调配空间 从first开始复制n个值到新空间中, 并返回新开拓的空间的首地址 iterator __allocate_and_copy(iterator first, size_type n){ //内存申请 iterator result = (iterator)malloc(n*sizeof(T)); iterator _start = result; if (0 != result){ while(n--){ construct(result, *first); ++result; ++first; } cout << endl; } else{ cout << "内存不足,程序终止!" << endl; exit(0); } return _start; }//将first到last迭代器之间(first,last)的元素拷贝到_start开始的内存中, 并返回 指向 拷贝完所有数据之后最初一个数据的下一个地位的指针 iterator __copy(iterator first, iterator last, iterator _start){ while (first < last){ *_start++ = *first++; } return _start; }//将first到last迭代器之间(first,last)的元素从新赋值iterator __fill(iterator first, iterator last, const T& value){ while (first < last){ *first++ = value; } return first;}//本人写的 从迭代器first开始填充n个值为value的元素iterator __fill_n(iterator first, size_type n, const T& value){ while (n--){ *first++ = value; } return first;}//本人写的 将从 [first,last)所有元素 一一顺次后移, 最初的一个元素移到end的地位void __backCopy(iterator first, iterator last, iterator end){ while (last >= first){ // *end-- = *last--; }}供内部应用的接口: ...

July 11, 2021 · 6 min · jiezi

关于c++:C仅根据函数返回值类型不能实现重载

函数的两个因素:参数与返回值。 如果同名函数的参数不同(包含类型、程序不同),那么容易区别出它们是不同的函数。 如果同名函数仅仅是返回值类型不同,有时能够辨别,有时却不能。例如: void Function(void);int Function (void);上述两个函数,第一个没有返回值,第二个的返回值是int 类型。如果这样调用函数:int x = Function (); 则能够判断出Function 是第二个函数。问题是在C++/C 程序中,咱们能够疏忽函数的返回值。在这种状况下,编译器和程序员都不晓得哪个Function 函数被调用。所以只能靠参数而不能靠返回值类型的不同来辨别重载函数。编译器依据参数为每个重载函数产生不同的外部标识符。 void Function(void){};int Function(void){};注:仅仅依据函数返回值不能重载函数,仅能依据不同的形参列表,包含参数个数和类型;仅仅依据参数返回类型编译器会收回谬误正告,在编译期间就提醒谬误

July 11, 2021 · 1 min · jiezi

关于c++:C-Primer-Plus-第01章-预备知识-学习笔记

第一章 准备常识1、C++简介C++交融了3种不同的编程形式: C语言代表的过程性语言C++在C语言根底上增加了类代表的面向对象语言C++模板反对的泛型编程C++继承C语言高效、简洁、疾速和可移植性的传统。 2、C++简史2.1 C语言编程:过程性语言Bell实验室的Dennis Ritchie为了设计开发UNIX的通用性、可移植性等,在旧语言的根底上开发了C语言。 汇编语言依赖于计算机的外部机器语言,间接对硬件进行操作。 数据:程序应用和解决的信息。 算法:程序应用的办法。 C语言是 过程性语言 ,强调编程的算法方面。一种结构化的编程形式。 C语言的新准则:自顶向下设计,现实:将大型程序拆分小型、便于管理的工作。 2.2 面向对象编程过程性语言(C语言)强调算法,OOP(C++、Java等)强调数据 。 OOP不像过程性编程,其理念是设计与问题的实质个性绝对应的数据格式。区别如下: 过程性语言(让问题来满足语言)OOP编程(让语言来满足问题)在C++中,类是一种标准,形容了新型数据格式,对象则依据类标准结构的特定数据结构。 类规定了可应用哪些数据来示意对象以及能够对这些数据执行哪些操作。 OOP程序设计办法:先设计类(能够明确示意程序要解决的货色),而后设计应用类的对象的程序。 从低级组织(如类)到高级组织(如程序)的处理过程叫作 自下而上 的编程思维。 类定义 = 数据 + 办法 OOP能够创立可重用的代码,缩小大量的工作,信息暗藏能够爱护数据,使其免遭不适当的拜访。 不同的环境(Windows和Macintosh)下提供编程的类库,能够不便地重用和批改现有的、通过认真测试的代码。 2.3 C++和泛型编程泛型编程(generic programming)是C++反对的另一种编程模式。与OOP指标零碎。 术语:泛型(指创立独立于类型的代码)。 OOP与泛型编程的区别: OOP强调编程的数据方面,是治理大型项目的工具泛型编程强调独立于特定数据类型,提供执行常见工作(如对数据排序或合并链表)的工具。C++泛型编程须要对语言进行扩大,以便于能够只编写一个泛型(即不是特定类型的)函数,并将其用于各种理论类型。 3、可移植性和规范C++是C语言的超集,任何无效的C程序都是无效的C++程序。 3.1 可移植性的两个阻碍硬件:分块搁置模块,通过重写模块,最大限度升高可移植性问题。语言上的差异性:国内组织定义了C语言规范、定义了C++99、C++11、C++14等规范。3.2 C++的二重性OOP提供了高级形象C提供了低级硬件拜访 C++既能够通过OOP进行形象,也可实现相似C一样的对硬件拜访的操作。 4、程序创立的技巧4.1 编程步骤更多编译细节请浏览【编译原理】 4.2 常见的编译器Linux/UNIX : GNU gcc/g++Windows :软件IDEMac OS : Xcode自带g++和clangGitHub地址:https://github.com/SolerHo/cp...

July 10, 2021 · 1 min · jiezi

关于c++:C-Primer-Plus-第02章-开始学习C-学习笔记

第二章 开始学习C++1. 进入C++/*第一个C++程序*/#include <iostream>using namespace std; /*定义一个可视化*/int main(void){ cout<<"Come up an C++"<<endl; cout<<"You won't regret it"<<endl; return 0;}对于一个C++ 程序次要蕴含以下元素: 正文:由前缀// 或者是 /* */ 标识预处理器编译指令#include函数头:int main() 编译指令:using namespace函数体:用{ } 括起来应用C++ 的cout工具显示音讯的语句完结main()函数的return语句1.1、main()函数头main() 被启动代码调用,而启动代码是编译器增加到程序中。 函数头形容 main() 和OS(UNIX/Linux、Windows、mac os等)间接的接口。空括号的main() 不承受任何参数。 int main(void){ statement return 0;}main()函数形容了函数的行为。同时也形成了两局部的 函数定义(function definition) :第一行int main()函数叫做 函数头(function heading),花括号({和})中包含的局部叫 函数体。 函数体:指出函数应做什么的计算机指令。 在C++中,每条残缺的指令叫做语句。所有的语句都是以 分号完结。 main()中最初一条语句叫做 返回语句(return statement),完结main()函数。 ⚠️留神:C++程序通常是以main() 函数开始执行,如果没有,程序不残缺,则编译器会指出未定义main()函数。 大小写都必须精确 不须要main()函数的非凡状况: Windows中的动静链接(DLL)模块。单片机或机器人芯片1.2、C++正文C++中的正文以 双斜杠(//) 打头。以行尾作为完结。 正文的作用:为程序提供解释阐明,使得程序通俗易懂。 通常标识程序的一部分或者是标识代码的某个方面。 留神点:编译器不会运行,会间接疏忽正文。 C++也能够辨认C语言的正文 C语言格调的正文 多行正文:符号/* 和 */ 之间,以 */ 作为正文的完结。单行正文:以 双斜杠(//) 开始,行尾作为完结。1.3、预处理器和头文件如果程序要应用C++输出或输入工具时,必须应用两行代码: ...

July 10, 2021 · 2 min · jiezi

关于c++:C-new和delete运算符

一、前言学习过C语言会晓得,在C语言中,动静分配内存用malloc()函数,开释内存用free()函数。在C++中这2个函数还是能够应用的,然而C++新增了2个关键字:new和delete。new 用来动静分配内存,delete 用来开释内存。咱们能够这样应用: int* p = new int;delete p;或int* pArray= new int[20];delete[] pArray;new 操作符会依据前面的数据类型来推断所需空间的大小。由上可知,应用new调配的内存用delete开释,应用new[]调配的内存用delete[]开释,它们是一一对应的。new申请空间时会多申请4个字节,用于寄存对象的个数,在返回地址时则会向后偏移4个字节,在delete时则会查看内存上对象的个数,依据个数确定调用几次析构函数,这样能力齐全清理所有对象占用的内存,因而对于内置类型若new[],应用delete开释,没有影响;但若是自定义类型,应用delete开释时只会调用一次析构函数,就会存在有对象没有被析构的状况。 new是在自在存储区上分配内存(能够在堆上,也能够在动态存储区上,取决于operator new实现细节,取决与它在哪里为对象调配空间),必须手动开释,否则只能等到程序运行完结由操作系统回收。为了防止内存透露,new 和 delete、new[] 和 delete[] 操作符应该成对呈现,并且不要和C语言中 malloc()、free() 一起混用。在C++中最好应用new和delete治理内存,比C语言的malloc和free多了能够主动调用构造函数和析构函数,这样在程序运行完结时能够开释内存。 二、new、delete和malloc、free的区别1、new和deletenew在操作时,内存通过 operator new 函数被调配,而且会为被调配的内存调用一个或多个构造函数构建对象;new内置了sizeof、类型转换和类型安全检查性能,对于非外部数据类型的对象而言,new 在创立动静对象的同时实现了初始化工作。如果对象有多个构造函数,那么new 的语句也能够有多种形式。如: int *p= new int[100](1);// 创立100 个动静对象的同时赋初值1 delete时,会为将被开释的内存调用一个或多个析构函数,还会通过 operator delete 函数开释内存。 2、malloc和freemalloc的函数原型为 void *malloc(long NumBytes)由原型可知,调用malloc时须要指定分配内存的字节数,胜利调配的话就返回对应的指针,指向被调配的内存块起始地位;否则返回空指针。 free的函数原型为: void free(void *p)将之前用malloc调配的空间还给程序或者操作系统,即对malloc申请的内存空间进行开释。free函数开释的是指针指向的内存(不是开释的指针自身,不会删除指针自身), 其中指针必须指向所开释内存空间的首地址。如果p 不是NULL 指针,那么free 对p间断操作两次就会导致程序运行谬误。 3、本质区别1)malloc/free是C/C++语言的规范库函数,new/delete是C++的运算符2)new能够主动分配内存空间,malloc须要指定申请空间的大小3)对于用户自定义的对象而言,malloc/free无奈满足动静治理对象的要求。因为malloc/free是库函数而不是运算符,不再编译器管制权限之内,不可能把执行构造函数和析构函数的工作强加于malloc/free。 new/delete能够被重载,malloc/free不能够;new/delete底层是基于malloc/free实现的;malloc分配内存之后发现不够,可通过realloc函数对其进行裁减或放大; malloc申请内存时返回内存地址要查看判空,因为申请失败时返回NULL;new不必判断,在内存调配失败时会抛出异样bac_alloc,因而可在new时加上异样解决机制,如: int* p = new(std::nothrow) int[10];为什么还保留了malloc和free?C++程序常常要调用C函数,而C程序 只能用malloc/free治理动态内存。若应用free开释new创立的动静对象,对象会因无奈执行析构函数而导致程序出错。若delete开释malloc申请的动态内存,可能不会出错,但程序的可读性差。

July 10, 2021 · 1 min · jiezi

关于c++:CSE-230难点分析

CSE 230 Project 4: Pardon the InterruptionLearning Objectives:● Implement an interrupt service routine in a program containing existing functionalityThe TaskIn this project, you will be adding an interrupt service routine (ISR) to an existing program. The program isalready fully functional hexadecimal counter that shows the current counter value on the seven-segmentdisplay. You will use the timer to generate an interrupt every x cycles (where x can be between 100 and 200cycles). Your ISR needs to do the following things: ...

July 10, 2021 · 1 min · jiezi

关于c++:C-STL-multiset容器

一、前言multiset容器和set容器惟一的差异在于:multiset容器容许存储多个值雷同的元素,而set容器中只能存储互不雷同的元素。 multiset容器类模板定义: template < class T, // 存储元素的类型 class Compare = less<T>, // 指定容器外部的排序规定 class Alloc = allocator<T> > // 指定分配器对象的类型> class multiset;multiset 类模板有3个参数,其中后2个参数自带有默认值。在理论应用中,咱们最多只须要应用前2个参数即可,第3个参数不会用到。 二、创立multiset容器multiset 类模板提供的构造函数,和 set 类模板中提供创立 set 容器的构造函数,是完全相同的。因而创立set容器的形式实用于创立multiset容器。具体的办法参考set容器:https://segmentfault.com/a/11... 三、办法办法阐明begin()返回指向容器中第一个(留神,是已排好序的第一个)元素的双向迭代器。如果 multiset 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器end()返回指向容器最初一个元素(留神,是已排好序的最初一个)所在位置后一个地位的双向迭代器,通常和 begin() 联合应用。如果 multiset 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器rbegin()返回指向最初一个(留神,是已排好序的最初一个)元素的反向双向迭代器。如果 multiset 容器用 const 限定,则该办法返回的是 const 类型的反向双向迭代器。rend()返回指向第一个(留神,是已排好序的第一个)元素所在位置前一个地位的反向双向迭代器。如果 multiset 容器用 const 限定,则该办法返回的是 const 类型的反向双向迭代器。cbegin()和 begin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值cend()和 end() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值。crbegin()和 rbegin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值crend()和 rend() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值find(val)在 multiset 容器中查找值为 val 的元素,如果胜利找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 办法一样的迭代器。另外,如果 multiset 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器lower_bound(val)返回一个指向以后 multiset 容器中第一个小于或等于 val 的元素的双向迭代器。如果 multiset 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器upper_bound(val)返回一个指向以后 multiset 容器中第一个大于 val 的元素的迭代器。如果 multiset 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器equal_range(val)该办法返回一个 pair 对象(蕴含 2 个双向迭代器),其中 pair.first 和 lower_bound() 办法的返回值等价,pair.second 和 upper_bound() 办法的返回值等价。也就是说,该办法将返回一个范畴,该范畴中蕴含所有值为 val 的元素empty()若容器为空,则返回 true;否则 falsesize()返回以后 multiset 容器中存有元素的个数max_size()返回 multiset 容器所能包容元素的最大个数,不同的操作系统,其返回值亦不雷同insert()向 multiset 容器中插入元素erase()删除 multiset 容器中存储的指定元素swap()替换 2 个 multiset 容器中存储的所有元素。这意味着,操作的 2 个 multiset 容器的类型必须雷同clear()清空 multiset 容器中所有的元素,即令 multiset 容器的 size() 为 0emplace()在以后 multiset 容器中的指定地位间接结构新元素。其成果和 insert() 一样,但效率更高emplace_hint()实质上和 emplace() 在 multiset 容器中结构新元素的形式是一样的,不同之处在于,使用者必须为该办法提供一个批示新元素生成地位的迭代器,并作为该办法的第一个参数count(val)在以后 multiset 容器中,查找值为 val 的元素的个数,并返回绝对于set容器,count()、find()、lower_bound()、upper_bound()、equal_range()等办法更罕用于multiset容器。 ...

July 10, 2021 · 1 min · jiezi

关于c++:C二维数组按行遍历与按列遍历的速度比较

1.程序:#include<cstdio>#include<cstdlib>#include<sys/time.h>#include<sys/resource.h>// 从进行开始执行到实现所经验的墙上时钟工夫(wall clock)工夫,// 包含其余过程应用的工夫片(time slice)和本过程消耗在阻塞(如期待I/O操作实现)上的工夫// CPU工夫是指过程占用CPU的工夫,过程阻塞的工夫则不会计入CPU工夫void gettime(double *cpu){ struct rusage ru; if(cpu != NULL) { getrusage(RUSAGE_SELF, &ru); *cpu = ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 1e-6; }}int main(int argc,char* argv[]){ int count = 20000; double cpu0,cpu1,cpu2; int* arr = (int*)malloc(sizeof(int) * count * count); int i,j; gettime(&cpu0); // 按行遍历二维数组 for(i=0;i<count;i++) { for(j=0;j<count;j++) { arr[i * count + j]=1; //printf("%d-%d ",i,j); } } // printf("\n"); gettime(&cpu1); // 按列遍历二维数组 for(i=0;i<count;i++) { for(j=0;j<count;j++) { arr[j * count + i]=1; // printf("%d-%d ",j,i); } } // printf("\n"); gettime(&cpu2); printf("按行遍历二维数组CPU时间差:%lf\n",cpu1-cpu0); printf("按列遍历二维数组CPU时间差:%lf\n",cpu2-cpu1); return 0;}测试机器:处理器:Apple M1内存:8g ...

July 9, 2021 · 1 min · jiezi

关于c++:STLemplaceback-和-pushback-的区别

性能问题:在引入右值援用,转移构造函数,转移复制运算符之前,通常应用push_back()向容器中退出一个右值元素(长期对象)的时候,首先会调用构造函数结构这个长期对象,而后须要调用拷贝构造函数将这个长期对象放入容器中。原来的长期变量开释。这样造成的问题是长期变量申请的资源就节约。 引入了右值援用,转移构造函数后,push_back()右值时就会调用构造函数和转移构造函数。 在这下面有进一步优化的空间就是应用emplace_back(),应用emplace_back()在容器尾部增加一个元素,这个元素原地结构,不须要触发拷贝结构和转移结构。而且调用模式更加简洁,间接依据参数初始化长期对象的成员。 #include <vector>#include <string>#include <iostream>struct President{ std::string name; std::string country; int year; President(std::string p_name, std::string p_country, int p_year) : name(std::move(p_name)), country(std::move(p_country)), year(p_year) { std::cout << "I am being constructed.\n"; } President(const President& other) : name(std::move(other.name)), country(std::move(other.country)), year(other.year) { std::cout << "I am being copy constructed.\n"; } President(President&& other) : name(std::move(other.name)), country(std::move(other.country)), year(other.year) { std::cout << "I am being moved.\n"; } President& operator=(const President& other);};int main(){ std::vector<President> elections; std::cout << "emplace_back:\n"; elections.emplace_back("Nelson Mandela", "South Africa", 1994); //没有类的创立 std::vector<President> reElections; std::cout << "\npush_back:\n"; reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936)); std::cout << "\nContents:\n"; for (President const& president: elections) { std::cout << president.name << " was elected president of " << president.country << " in " << president.year << ".\n"; } for (President const& president: reElections) { std::cout << president.name << " was re-elected president of " << president.country << " in " << president.year << ".\n"; }}源码分析:push_back: ...

July 6, 2021 · 2 min · jiezi

关于c++:C-explicit-关键字

隐式类型转换 (构造函数的隐式调用)举例: #include <iostream>using namespace std;class Point {public: int x, y; Point(int x) : x(x) {}};void displayPoint(const Point& p) { cout << "(" << p.x << ")" << endl;}int main(){ displayPoint(1); Point p = 1;}explicit关键字 指定构造函数或转换函数 (C++11起)为显式, 即它不能用于隐式转换和复制初始化.构造函数被explicit润饰后, 就不能再被隐式调用了. 也就是说, 之前的代码, 在Point(int x)前加了explicit润饰, 就无奈通过编译了. //退出explicit关键字后#include <iostream>using namespace std;class Point {public: int x, y; explicit Point(int x) : x(x) {}};void displayPoint(const Point& p) { cout << "(" << p.x << ")" << endl;}int main(){ displayPoint(1); Point p = 1;}Effective C++: ...

July 6, 2021 · 1 min · jiezi

关于c++:Write-a-program

F. Task(s) Write a program to sort an array of size 10 using both Merge and Quick sort algorithms.Make sure that both algorithms collaborate to sort one dimensional array, i.e. if merge sortis applied on the first part of the array then Quick sort must be applied on the other part asshown in the following figure:Make sure to follow the following rules:a. You are not allowed to apply each algorithm on the entire array.b. If one algorithm applied for one part, then the other algorithm applied to the rest of thearray. For example mergeSort(arr,0,4) then quicksort(arr,5,n-1).c. Make sure that your code works on any input.d. Never use any other sorting algorithms.e. You are only allowed to apply algorithms with O(n) complexity other than Merge andQuick sort.f. Make sure that your final array is sorted after both Merge and Quick sort algorithmsfinish.Sort elements in ascending order using stack, i.e. make the smallest element to be the topelement of the stack. For example, given the stack elements (from bottom to top): 5, 2, 6,9, sort the elements to make the stack elements become (from bottom to top): 9, 6, 5, 2.The only data structure you can use is array-based stack. Given a stack st, use one extrastack, tmpst, to store temporary data.Merge sort Quick sortNot sortedSorteda. Write a C++ program to sort elements in an array-based stack in ascending order.b. Demonstrate the sorting process with given input numbers {25, 10, 15, 20, 30}.Algorithm:pop out the st to a variable tmp until it finishes all elements.while tmpst is not emptyif the top element of tmpst is smaller than tmp,pop out tmpst and push that element onto stpush tmp onto tmpst ……Sample output (Example):Note: implement the Stack class with all necessary functionality.APPENDIX 1MARKING RUBRICSComponent Title Mergesort and Quicksort Percentage(%) 50CriteriaScore and Descriptors Weight(%) Marks(50-40) (40-30) (30-15) (15-10) (10-0)WX:codehelp ...

July 5, 2021 · 2 min · jiezi

关于c++:数据结构-哈希表

数据结构 哈希表 什么是哈希表 Hash表也称散列表,也有间接译作哈希表,Hash表是一种依据关键字值(key - value)而间接进行拜访的数据结构。它基于数组,通过把关键字映射到数组的某个下表来放慢查找速度,然而又和数组、链表、树等数据结构不同,在这些数据结构中查找某个关键字,通常要遍历整个数据结构,也就是O(N)的工夫级,然而对于哈希表来说,只是O(1)的工夫级。留神,这里有个重要的问题就是如何把关键字转换为数组的下标,这个转换的函数称为哈希函数(也称散列函数),转换的过程称为哈希化。个别哈希表都是用来疾速判断一个元素是否呈现在汇合中。图片哈希函数它把一个大范畴的数字哈希(转化)成一个小范畴的数字,这个小范畴的数对应着数组的下标。应用哈希函数向数组插入数据后,这个数组就是哈希表。哈希抵触 链地址法 --(拉链法)这种办法的根本思维是将所有哈希地址为i的元素形成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因此查找、插入和删除次要在同义词链中进行。链地址法实用于常常进行插入和删除的状况。线性探测法长处:易于施行;总是找到一个地位(如果有);当表不是很满时,均匀状况 下的性能十分好。毛病:表的相邻插槽中会造成“集群”或“集群”键;当这些簇填满整个阵列的大部 分时,性能会重大降落,因为探针序列执行的工作实际上是对大部分阵列的穷举搜寻。哈希表的长处能够像数组一样通过下标随机拜访。补救了数组只能通过整数索引拜访的缺点。哈希表的毛病每次存取数据之前要通过散列函数计算对应的散列值,耗费了更多内存。装载因子 是散列表性能的衡量标准之一。因为散列表实际上还是数组,所以能承载的数据是无限的,当哈希表存储的数据超过数组索引的长度时则必然会呈现散列抵触。 常见的三种哈希构造当咱们想应用哈希法来解决问题的时候,咱们个别会抉择如下三种数据结构。数组set(汇合)map(映射)在C++语言中,实现在C++中,set 和 map 别离提供了以下三种数据结构,其底层实现以及优劣如下表所示:图片红黑树是一种均衡二叉搜寻树,所以key值是有序的,但key不能够批改,改变key值会导致整棵树的错乱,所以只能删除和减少。 图片 std::map 和std::multimap的key也是有序的(这个问题也常常作为面试题,考查对语言容器底层的了解)。当咱们要应用汇合来解决哈希问题的时候,优先应用unordered_set,因为它的查问和增删效率是最优的,如果须要汇合是有序的,那么就用set,如果要求不仅有序还要有反复数据的话,那么就用multiset。那么再来看一下map ,在map 是一个key value 的数据结构,map中,对key是有限度,对value没有限度的,因为key的存储形式应用红黑树实现的。总结总结一下,当咱们遇到了要疾速判断一个元素是否呈现汇合里的时候,就要思考哈希法。然而哈希法也是就义了空间换取了工夫,因为咱们要应用额定的数组,set或者是map来存放数据,能力实现疾速的查找。 本文由博客一文多发平台 OpenWrite 公布!

July 4, 2021 · 1 min · jiezi

关于c++:COMP2396

COMP2396Due: 14 April, 2019, 23:55IntroductionThis assignmenttests your skills on writing simple JavaGUI program, using Java graphics andevents.YouneedtowriteapuzzleprogramJavaPuzzle.java,whichallows theusertoselectanimage as a puzzle and the user can then play with the selected images.This assignment will be evaluated on both functionality and program design. You can getpart ofthe full marks if you implement some ofthe features.You are expected to use Java GUI graphics to display the userinterface ofthis assignment.YouarealsorequiredtowriteJavaDocforallnon-privateclassesandnon-privateclassmembers. Programs without JavaDoc will not be marked.Part I Select an ImageWhenJavaPuzzleisexecuted,afilechoosershouldbepresentedtoaskforanimagefile.Part II Display the Image and randomize the imageTheimageisloadedfromtheselectedfileandisdividedintoblocksof80*80pixelsinsize displayed as shown in above figure. The blocks ofthe image are randomized so thatthe user will not see the original image.Ifthe image file fails to load,the program shouldgenerateanerrormessageandasktheusertoselectanotherimagefile.Eachimageblockshouldkeepitsoriginalpositioninformationsothattheoriginalimagecanbereconstructed.Your main UI should contain the following: ...

July 4, 2021 · 3 min · jiezi

关于c++:CCTSCMICC

include <stdio.h>include "tulip.h"include "TSCMI.h"define _CHECK_BUFLEN_DEMAND_RETFALSE(done, total, demand) \do { \ if ((done+demand) > total) \{ \ if (dbg_TSCPrt) \ { \ printf("[%s:%d]EPMS TotalLen not enough. total:%u, demand:%u\n", __FUNCTION__, __LINE__, (WORD32)total, (WORD32)demand); \ } \ return FALSE; \} \} while (0) ifdef LITTLE_ENDIANdefine _GET_NTOH16(ptrbyte) (WORD16)(((((WORD16 )(ptrbyte))>>8) & 0xff) | (((WORD16 )(ptrbyte))<<8))define _GET_NTOH32(ptrbyte) (WORD32)(((((WORD32 )(ptrbyte))>>24) & 0xff) | ((((WORD32 )(ptrbyte))>>8) & 0xff00) | ((((WORD32 )(ptrbyte))<<8) & 0xff0000) | (((WORD32 )(ptrbyte))<<24))define _GET_NTOH64(ptrbyte) (WORD64)(((((WORD64 )(ptrbyte)) & 0xff00000000000000) >> 56) | \ (((*(WORD64 *)(ptrbyte)) & 0x00ff000000000000) >> 40) | \ (((*(WORD64 *)(ptrbyte)) & 0x0000ff0000000000) >> 24) | \ (((*(WORD64 *)(ptrbyte)) & 0x000000ff00000000) >> 8) | \ (((*(WORD64 *)(ptrbyte)) & 0x00000000ff000000) << 8) | \ (((*(WORD64 *)(ptrbyte)) & 0x0000000000ff0000) << 24) | \ (((*(WORD64 *)(ptrbyte)) & 0x000000000000ff00) << 40) | \ (((*(WORD64 *)(ptrbyte)) & 0x00000000000000ff) << 56))define _SET_HTON16(ptrbyte, val) do {((WORD16 )(ptrbyte)) = ((((val)>>8) & 0xff) | ((val)<<8));} while (0)define _SET_HTON32(ptrbyte, val) do {((WORD32 )(ptrbyte)) = ((((val)>>24) & 0xff) | (((val)>>8) & 0xff00) | (((val)<<8) & 0xff0000) | ((val)<<24));} while (0)define _SET_HTON64(ptrbyte, val) do {((WORD64 )(ptrbyte)) = ((((val) & 0xff00000000000000) >> 56) | \ (((val) & 0x00ff000000000000) >> 40) | \ (((val) & 0x0000ff0000000000) >> 24) | \ (((val) & 0x000000ff00000000) >> 8) | \ (((val) & 0x00000000ff000000) << 8) | \ (((val) & 0x0000000000ff0000) << 24) | \ (((val) & 0x000000000000ff00) << 40) | \ (((val) & 0x00000000000000ff) << 56));} while (0)elsedefine _GET_NTOH16(ptrbyte) (WORD16)((WORD16 )(ptrbyte))define _GET_NTOH32(ptrbyte) (WORD32)((WORD32 )(ptrbyte))define _GET_NTOH64(ptrbyte) (WORD64)((WORD64 )(ptrbyte))define _SET_HTON16(ptrbyte, val) do {((WORD16 )(ptrbyte)) = (val);} while (0)define _SET_HTON32(ptrbyte, val) do {((WORD32 )(ptrbyte)) = (val);} while (0)define _SET_HTON64(ptrbyte, val) do {((WORD64 )(ptrbyte)) = (val);} while (0)endififndef MAXdefine MAX(x, y) (((x)>(y))?(x):(y))endififndef MINdefine MIN(x, y) (((x)<(y))?(x):(y))endifBOOLEAN dbg_TSCPrt = FALSE; ...

July 3, 2021 · 21 min · jiezi

关于c++:gdb命令使用

编译程序时须要加上-g,之后能力用gdb进行调试:gcc -g main.c -o main gdb pcefctrl_test进入GDB后,设置执行单条用例的命令:set args --gtest_filter=PcefctrlPolicyDetection.GIVEN_sess_crt_WHEN_build_detection_ruleInfo_THEN_build_detection_RuleInfo_ok执行一组用例集set args --gtest_filter=SetPackage.*gdb中命令: 回车键:反复上一命令 (gdb)help:查看命令帮忙,具体命令查问在gdb中输出help + 命令,简写h (gdb)run:从新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r (gdb)start:单步执行,运行程序,停在第一执行语句 (gdb)list:查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数),简写l (gdb)set:设置变量的值 (gdb)next:单步调试(逐过程,函数间接执行),简写n (gdb)step:单步调试(逐语句:跳入自定义函数外部执行),简写s (gdb)backtrace:查看函数的调用的栈帧和层级关系,简写bt (gdb)frame:切换函数的栈帧,简写f (gdb)info:查看函数外部局部变量的数值,简写i (gdb)finish:完结以后函数,返回到函数调用点 (gdb)continue:持续运行,简写c (gdb)print:打印值及地址,简写p (gdb)quit:退出gdb,简写q (gdb)break+num:在第num行设置断点,简写b (gdb)info breakpoints:查看以后设置的所有断点 (gdb)delete breakpoints num:删除第num个断点,简写d (gdb)display:追踪查看具体变量值 (gdb)undisplay:勾销追踪察看变量 (gdb)watch:被设置观察点的变量产生批改时,打印显示 (gdb)i watch:显示观察点 (gdb)enable breakpoints:启用断点 (gdb)disable breakpoints:禁用断点 (gdb)x:查看内存x/20xw 显示20个单元,16进制,4字节每单元 (gdb)run argv[1] argv[2]:调试时命令行传参 (gdb)set follow-fork-mode child#Makefile项目管理:抉择跟踪父子过程(fork()) core文件:先用$ ulimit -c 1024 开启core,当程序出错会主动生成core文件。调试时 gdb a.out core

July 3, 2021 · 1 min · jiezi

关于c++:COSC1076

COSC1076Advanced Programming TechniquesAssignment 1Particle FilterWeight: 15% of the final course markDue Date: 11.59 pm, Friday 5 April 2019 (Week 5)Learning Outcomes: This assignment contributes to CLOs: 1, 2, 3, 4, 6Change Log1.3 Added submission instructions Updated code description requirements for Milestone 4 Minor corrections in Background1.2 Updated references to classes Updated notes on Unit Tests to be clearer about the purpose of the sample unit tests. Updated parts of the Task descriptions to be clearer Added Section "Getting Started"1.1 Corrected positions on the worked example. Updated compilation command, removing -c from full code command.1.0 Initial Release1Contents1 Introduction 31.1 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Relevant Lecture/Lab Material . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.3 Start-up Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.4 Plagiarism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Background 42.1 Particle Filter Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 Worked Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Task 73.1 Milestone 1: Unit Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73.2 Milestone 2: Particle Filter API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73.2.1 Particle Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.2.2 ParticleList Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.2.3 ParticleFilter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93.2.4 Code Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103.2.5 Code Style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103.2.6 Mandatory Requirements and Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . 103.3 Milestone 3: Unknown Orientation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103.4 Milestone 4: Efficient Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113.4.1 Code Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Starter Code 124.1 Running Unit Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124.2 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Submission Instructions 135.1 Submitting Code Files (.h/.cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135.2 Submitting Unit Tests (.maze/.obs/.pos) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1321 Introduction1.1 SummaryIn this assignment you will implement an algorithm known as a Particle Filter, and use it with a simplesimulated 2D robot moving around a room.In this assignment you will: Practice the programming skills covered throughout this course, such as:– Pointers– Dynamic Memory Management– Provided API Correctly Implement a pre-defined API Implement a medium size C++ program Use a prescribed set of C++11/14 language featuresThis assignment is divided into four Milestones: Milestone 1: Writing Unit Tests Milestone 2: Minimum required component for implementing the simple particle filter Milestone 3: Optional component to extend the particle filter for map rotations Milestone 4: Optional component for efficient memory management1.2 Relevant Lecture/Lab MaterialTo complete this assignment, you will requires skills and knowledge from lecture and lab material for Weeks 2 to4 (inclusive). You may find that you will be unable to complete some of the activities until you have completedthe relevant lab work. However, you will be able to commence work on some sections. Thus, do the work youcan initially, and continue to build in new features as you learn the relevant skills.1.3 Start-up CodeOn Canvas you will find starter code to help you get running with the assignment. This code includes: Dummy (empty) code files, for you to implement Unit Testing code, to help you write and run tests on your implementation Example Unit Test cases1.4 Plagiarism!Plagiarism is a very serious offence.A core learning outcomes for this course is for you to: Demonstrate and Adhere to the standards and practiceof Professionalism and Ethics, such as described in the ACS Core Body of Knowledge (CBOK) for ICTProfessionals.The penalty for plagiarised assignments include zero marks for that assignment, or failure for this course.Please keep in mind that RMIT University uses plagiarism detection software to detect plagiarism and that allassignments will be tested using this software. See the RMIT website for more information about the universitypolicies on Plagiarism and Academic Misconduct.32 BackgroundOne challenge in robotics is called localisation. This is the process of the robot figuring out where it is withinsome environment. One algorithm for localising a robot is called a Particle Filter. In this assignment youwill implement a simple particle filter for a robot moving about a simple 2D maze.In this assignment, the simple 2D maze will be represented as a grid of ASCII characters. For example:Aspects of the maze are represented by different symbols:Symbol Meaning. (dot) Empty/Open Space. The robot can enter any open space.= (equal) Wall or Obstacle within the maze. The robot cannot pass obstacles~ (tilda) The edge of the maze. Every maze is always bounded by the edge symbolsEach location in the maze (including the maze edges) is indexed by a cartesian (x,y) co-ordinate. The top-leftcorner of the maze is always the co-ordinate (0,0), the x-coordinate increases right-wards, and the y-coordinateincreases down-wards. For the above maze, the four corners have the following co-ordinates:For the purposes of this assignment we will make two assumptions: ...

July 3, 2021 · 20 min · jiezi

关于c++:swoole467golangpythoncclinux核心技术底层分析到微服务实战

https://www.bilibili.com/vide...

July 2, 2021 · 1 min · jiezi

关于c++:解讲CCSCI251CSCI851

School of Computing & Information TechnologyCSCI251/CSCI851 Advanced ProgrammingAutumn 2019Assignment 1 (Worth 10%)Due 11:55pm Friday 5th April 2019. (End of Week Five)OverviewThis assignment is to be implemented using procedural programming. The overall program should processanimals through a veterinary (Vet) clinic. This is not supposed to be a sensible simulation of such a clinic,and does not comply with typical operating practices for such centres.General code notesThese are some general rules about what you should and shouldn’t do. ...

June 30, 2021 · 6 min · jiezi

关于c++:在C中你真的会用new吗

摘要:“new”是C++的一个关键字,同时也是操作符。对于new的话题十分多,因为它的确比较复杂,也十分神秘。本文分享自华为云社区《如何编写高效、优雅、可信代码系列(2)——你真的会用new吗》,原文作者:我是一颗大西瓜 。 C++内存治理1. C++内存调配C++中的程序加载到内存后依照代码区、数据区、堆区、栈区进行布局,其中数据区又能够分为自在存储区、全局/动态存储区和常量存储区,各区所长如下: 栈区函数执行的时候,局部变量的存储单元都在栈上创立,函数执行完结后存储单元会主动开释。栈内存调配运算内置于处理器指令集中,效率高,但调配内存容量无限。堆区堆就是new进去的内存块,编译器不论开释,由利用程序控制,new对应delete。如果没开释掉,程序完结后,操作系统会主动回收。自在存储区C中malloc调配的内存块。用free完结生命周期。全局/动态存储区全局变量和动态变量被调配到同一块内存中,定义的时候就会初始化。常量存储区比拟非凡的存储区,寄存常量,不容许批改。堆和栈的区别 治理形式栈由编译器主动治理,堆由程序员管制空间大小32位零碎下,堆内存能够达到4GB,栈有肯定的空间大小碎片治理对于堆,频繁的new/delete必定造成内存空间的不间断,产生大量内存碎片升高程序效率;栈因为遵循先进后出的规定,不会产生空隙成长方向堆是向上成长的,即向着内存地址减少的方向增长;而栈是向着内存地址减小的方向增长的调配形式堆是动态分配的,栈有动态分配和动态调配之分:动态调配由编译器实现,动态分配由alloca函数实现,即便是动态分配,仍然是编译器主动开释调配效率计算机底层提供了栈的反对,调配了专门的寄存器寄存栈的地址,压栈出栈都有专门的指令执行,这决定了栈的效率会比拟高。堆则是由C/C++函数库提供的,机制比较复杂,比方为了调配某个大小的内存须要在堆内存中搜寻可用足够大小的空间,效率比栈要低的多2. new/delete和new []/delete []回收new调配的单个对象内存空间时用delete,回收用new[]调配的一组对象时用delete[]对于内置类型(int/double/float/char/…),因为new[]申请内存时,编译器还会轻轻在内存中保留整数,示意指针数组的个数,所以delete/delete[]都能够正确开释所申请的内存空间倡议在调用new时应用的[],那么调用delete也应用[]3. new的三种状态new operator 罕用的new,语言函数内建,不能重载。调用过程中理论实现的有三件事:为类型对象分配内存;调用构造函数初始化内存对象;返回对象指针如果是在堆上建设对象,间接应用new operator。operator new 一般操作符,能够重载。如果仅仅是分配内存,那么应该调用operator new,但不负责初始化。零碎默认提供的分配器在工夫和空间两方面都存在一些问题:分配器速度较慢,调配小型对象时空间节约重大,重载new/delete有三方面益处:改善效率检测代码中的内存谬误取得内存应用的统计数据C++标准规定,重载的operator new必须是类成员函数或全局函数,全局的operator new重载不应该扭转原有签名,而是间接无缝替换原有版本。全局重载很有侵略性,他人应用你的库无奈应用默认的new,而具体类的重载只会影响本class和其派生类,然而类的operator new函数重载必须申明为static,因为operator new是在类的具体对象被构建进去之前调用的。为了取得2和3的劣势,重载的operator new须要如下函数申明void operator new(size_t, const char file, int line);placement new 定义在库<<new>>中。如果想在一块曾经取得内存里建设对象,那么应该调用placement new。通常状况不倡议应用,但在某些对工夫要求十分高的利用中能够思考,因为抉择适合的构造函数实现对象初始化是一个工夫绝对较长的过程。点击关注,第一工夫理解华为云陈腐技术~

June 30, 2021 · 1 min · jiezi

关于c++:linux-网络编程-socket

1、开发流程图 2、socket中TCP的三次握手建设连贯详解 咱们晓得tcp建设连贯要进行“三次握手”,即替换三个分组。大抵流程如下: 客户端向服务器发送一个SYN J服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1客户端再想服务器发一个确认ACK K+1只有就完了三次握手,然而这个三次握手产生在socket的那几个函数中呢?请看下图: image 图1、socket中发送的TCP三次握手 从图中能够看出,当客户端调用connect时,触发了连贯申请,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连贯申请,即收到SYN J包,调用accept函数接管申请向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手结束,连贯建设。 3、网络字节序与主机字节序 主机字节序就是咱们平时说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保留的程序,这个叫做主机序。援用规范的Big-Endian和Little-Endian的定义如下: a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。 b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。 网络字节序:4个字节的32 bit值以上面的秩序传输:首先是0~7bit,其次8~15bit,而后16~23bit,最初是24~31bit。这种传输秩序称作大端字节序。因为TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种秩序,因而它又称作网络字节序。字节序,顾名思义字节的程序,就是大于一个字节类型的数据在内存中的寄存程序,一个字节的数据没有程序的问题了。 所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假设主机字节序跟网络字节序一样应用的是Big-Endian。因为这个问题曾引发过血案!公司我的项目代码中因为存在这个问题,导致了很多莫名其妙的问题,所以请谨记对主机字节序不要做任何假设,务必将其转化为网络字节序再赋给socket。

June 30, 2021 · 1 min · jiezi

关于c++:C内存管理18总结从最基础到最复杂

整顿于侯捷老师 《C++内存管理机制-从高山到万丈高楼》 视频内容 文档《C++内存管理机制-从高山到万丈高楼》pdf(来源于网络,非常感激) 测试环境ubuntu-18.4.3Qt 5.13.1Dev 5.11其余阐明免费视频来源于b站,可自行搜寻,C++内存管理机制-从高山到万丈高楼 课程简介内存是电脑中的“脑”吗?CPU才是脑,CPU才是计算机中的三魂六魄。但若没有内存,所有只存在于扑朔迷离间,等同于不存在。 内存已经是贵重也最低廉的周边资源,古代程序员无奈设想 Dos 时代对内存的斤斤计较。 俱往矣,且看今朝。咱们(仿佛)有用不完的便宜内存。但表象之下是操作系统和规范库做了大量工作。而如果你开发内存高耗软件,或处于内存受限环境下(例如嵌入式零碎),就有必要粗浅理解操作系统和规范库为你所作的内存寸治理,甚至须要自行治理内存。 课程分为6讲: 第一讲:PrimitivesC++ 语言中于内存相干的所有根底组件(constructs),包含 malloc/free, new/delete, operator new/operator delete, placement new/placement delete, 我将探讨他们的意义、使用形式和重载形式。并以此开发一个小型内存池(memory pool)。 Overview内存调配的每个层面四个根本层面的用法根本构件之一 new/delete expressions根本构件之二 array new/delete根本构件之三 placement new/delete根本构建之调配流程根本构建之重载Per-class allocatorPer-class allocatorCommon static allocator (第三版)Macro allocator(第四版)GNU C++ allocator(第五版)杂项探讨[以上章节在博客中进行了局部合并整顿]第二讲:std::allocator规范库的衰亡,意味着咱们能够解脱内存治理的重复琐碎,间接应用容器。然而容器背地的分配器(allocator)攸关容器的速度能效和空间能效。我将比拟 Visual C++, Borland C++, GUN C++ 规范库中的 allocator, 并深入探讨其中最精美的 GNU C++ allocator 的设计。 内存块布局VC6 allocatorBC5 allocatorGNU allocatorGNU allocator 行为分析GNU allocator 源码分析GNU allocator 探讨GNU allocator 监督GNU allocator 移植到 C 语言[以上章节在博客中进行了局部合并整顿]第三讲:malloc/freemalloc/free 是所有内存管理手段的最初一里;通过它才和操作系统搭上线。当然你也能够间接调用 system API, 但不倡议。因而了解 malloc/free 的外部治理至为重要。我将以 Visual C++ 的 CRT (C RunTime Library)所带的 malloc/free 源代码为根底,深度摸索这最根底最要害的内存调配于开释函数。 ...

June 29, 2021 · 1 min · jiezi

关于c++:带你掌握C中三种类成员初始化方式

摘要:在C++11之后,申明时初始化->初始化列表->构造函数初始化。本文分享自华为云社区《如何编写高效、优雅、可信代码系列(3)——类成员初始化的三种形式》,原文作者:我是一颗大西瓜。 首先,先得理解一下C++反对哪几种类成员初始化的形式,你罕用的又是哪一种。 初始化形式一:初始化列表class A{public: int a; // 初始化列表 A(int a_):a(a_){}};初始化形式二:构造函数初始化class A{public: int a; // 初始化列表 A(int a_, bool b) { a = a_; }};初始化形式三:申明时初始化(也称就地初始化,c++11后反对)class A{public: int a = 1; // 申明时初始化 A() {}};在C++98中,反对了在类申明中应用等号“=”加初始值的形式,来初始化类中动态成员常量。这种申明形式咱们也称之为“就地”申明。就地申明在代码编写时十分便当,不过C++98对类中就地申明的要求却十分高。如果动态成员不满足常量性,则不能够就地申明,而且即便常量的动态成员也只能是整型或者枚举型能力就地初始化。而非动态成员变量的初始化则必须在构造函数中进行。比方,如下代码在c++98中编译 class Init{public: Init(): a(0) [] Init(int d): a(d) {}private: int a; const static int b = 0; int c = 1; // member, cannot pass build static int d = 0; // member, cannot pass build static const double e = 1.3; // not int or enum type, cannot pass build stati const char* const f = "e"; // not int or enum type, cannot pass build}这十分不不便,所以在C++11中,规范容许非动态成员变量的初始化有多种形式。具体而言,除了初始化列表外,在C++11中,规范还容许应用等号= 或者 花括号{} 进行就地的非动态成员变量初始化。 ...

June 29, 2021 · 1 min · jiezi

关于c++:编程语言C-四种强制类型转换

一、const_cast1、常量指针被转化成十分量的指针,并且依然指向原来的对象; 2、常量援用被转换成十分量的援用,并且依然指向原来的对象; 3、const_cast个别用于批改指针。如const char *p模式。 #include<iostream>int main() { // 原始数组 int ary[4] = { 1,2,3,4 }; // 打印数据 for (int i = 0; i < 4; i++) std::cout << ary[i] << "\t"; std::cout << std::endl; // 常量化数组指针 const int*c_ptr = ary; //c_ptr[1] = 233; //error // 通过const_cast<Ty> 去常量 int *ptr = const_cast<int*>(c_ptr); // 批改数据 for (int i = 0; i < 4; i++) ptr[i] += 1; //pass // 打印批改后的数据 for (int i = 0; i < 4; i++) std::cout << ary[i] << "\t"; std::cout << std::endl; return 0;}out print: ...

June 28, 2021 · 3 min · jiezi