
c/c++
文章平均质量分 69
lliuhao--
贵在坚持
展开
-
虚函数表存储的位置(解析C++内存分配及其编译分段)
C语言在编译和连接后,将分成代码段(Text)、只读数据段(ROData)和读写数据段(RWData)。在运行时,除了以上三个区域外,还包括未初始化数据段(BSS)区域和堆(Heap)区域和栈(Stack)区域。虚函数表属于类,类的所有对象共享这个类的虚函数表。编译时期由编译器确定。原创 2023-09-11 11:17:04 · 1202 阅读 · 0 评论 -
编译链接的流程
链接过程中可能会生成动态链接文件(Dynamic Link Library,DLL)或静态链接文件(Static Link Library,LIB)。静态链接会将目标文件中需要使用的代码和数据复制到最终可执行文件中,而动态链接则将其保留为独立的文件,在程序运行时由操作系统动态加载。原创 2023-08-31 20:23:39 · 369 阅读 · 0 评论 -
C++ 左值和右值
在foo(i), 如果传入的是一个左值, 那么foo中T的类型将是int&, fparam类型是int& &&, 经过折叠为int&. 因此在std::forward模板函数中,推断出T的类型为int&,因此,std::remove_reference用int& 进行实例化。将亡值则是C++11新增的跟右值引用相关的表达式,这样表达式通常是将要被移动的对象(移为他用),比如返回右值引用T&&的函数返回值、std::move的返回值,或者转换为T&&的类型转换函数的返回值。返回string &&。原创 2023-08-03 23:49:38 · 580 阅读 · 0 评论 -
C++11移动构造函数详解
当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。C++在三种情况下会调用拷贝构造函数(可能有纰漏),第一种情况是函数形实结合时,第二种情况是函数返回时,函数栈区的对象会复制一份到函数的返回去,第三种情况是用一个对象初始化另一个对象时也会调用拷贝构造函数。除了这三种情况下会调用拷贝构造函数,另外如果将一个对象赋值给另一个对象,这个时候回调用重载的赋值运算符函数。原创 2023-08-03 23:38:09 · 531 阅读 · 0 评论 -
C++ 智能指针
默认情况下,智能指针使用 delete 释放其管理的资源,有时候,可能要修改默认使用 delete 释放资源的行为,除此之外,我们也可以自定义删除器。Connection 是一个管理连接类,在释放 Connection 之前,我们需要调用 close 函数来关闭连接。public :cout << string("关闭") + connection -> get_name() + "管理的连接中..." << endl;// 关闭连接的代码 // ..... cout << "关闭完成。原创 2023-08-03 23:32:47 · 213 阅读 · 0 评论 -
C++ rand的用法
功能: 随机数发生器用法: int rand(void)所在头文件: stdlib.hrand() 的内部实现是用线性同余法做的,它不是真的随机数,因其周期特别长,故在一定的范围里可看成是随机的。rand() 返回一随机数值的范围在 0 至 RAND_MAX 间。RAND_MAX 的范围最少是在 32767 之间(int)。用 unsigned int 双字节是 65535,四字节是 4294967295 的整数范围。0~RAND_MAX 每个数字被选中的机率是相同的。原创 2023-08-02 22:55:57 · 422 阅读 · 0 评论 -
C++中的五种构造函数
如果形参是一个对象,那么形参的值是否等于实参,取决于该对象所属的类的复制构造函数是如何实现的。例如上面的例子,Func 函数的形参 a 的值在进入函数时是随机的,未必等于实参,因为复制构造函数没有做复制的工作。换言之,作为函数返回值的对象是用复制构造函数初始化 的,而调用复制构造函数时的实参,就是 return 语句所返回的对象。换句话说,作为形参的类A的对象,是用复制构造函数初始化的,而且调用复制构造函数时的参数,就是调用函数时所给的实参。需要注意的是,默认的拷贝构造函数实现的是。这两条语句是等价的。原创 2023-08-02 22:52:46 · 1044 阅读 · 0 评论 -
C++ 虚函数详解(动态绑定)
虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。我们在使用基类的引用(指针)调用虚函数时,就会发生动态绑定。所谓动态绑定,就是在运行时,虚函数会根据绑定对象的实际类型,选择调用函数的版本。原创 2023-08-02 00:04:59 · 1035 阅读 · 0 评论 -
C++ 继承
本例中,Base 类的func()、func(int)和 Derived 类的func(char *)、func(bool)四个成员函数的名字相同,参数列表不同,它们看似构成了重载,能够通过对象 d 访问所有的函数,实则不然,Derive 类的 func 遮蔽了 Base 类的 func,导致第 26、27 行代码没有匹配的函数,所以调用失败。所谓遮蔽,就是在派生类中使用该成员(包括在定义派生类时使用,也包括通过派生类对象访问该成员)时,实际上使用的是派生类新增的成员,而不是从基类继承来的。原创 2023-08-01 23:56:29 · 243 阅读 · 0 评论 -
计算机网络模型
TCP/IP协议簇是Internet的基础,也是当今最流行的组网形式。其中比较重要的有SLIP协议、PPP协议、IP协议、ICMP协议、ARP协议、TCP协议、UDP协议、FTP协议、DNS协议、SMTP协议等。同理,ICMP、IGMP 属于 IP 层,但因为它们的报文会被封装到 IP 数据报中,因此画在了 IP 层靠上的位置。网络接口层的传输单位是帧(frame),IP 层的传输单位是包(packet),TCP 层的传输单位是段(segment),HTTP 的传输单位则是消息或报文(message)。原创 2023-07-22 21:03:43 · 1246 阅读 · 0 评论 -
C++多态
对于有相关功能的对象集合,我们总希望能够抽象出它们共有的功能集合,在基类中将这些功能声明为虚接口(虚函数),然后由子类继承基类去重写这些虚接口,以实现子类特有的具体功能。程序在编译之前就知道用哪个函数,即在一个类中有相同的函数名,也就是函数重载,重载函数的参数个数,参数类型或参数顺序三者中必须有一个不同。编译时多态基于template(模板)的具现化与函数的重载解析,这种多态在编译期进行,因此称为编译期多态。在不同但是具有继承关系的类中有相同的函数名,这样的实现方式也叫重写(编译器自动处理成虚函数)。原创 2023-07-21 22:21:19 · 53 阅读 · 0 评论 -
C++ 函数调用的压栈过程
调用fun()的过程大致如下:原创 2023-07-21 22:03:36 · 365 阅读 · 0 评论 -
C++内联函数详解
关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。// inline 仅与函数声明放在一起 void Foo(int x , int y) {. . . }inline void Foo(int x , int y) // inline 与函数定义体放在一起 {. . . }所以说,C++ inline函数是一种用于实现的关键字,而不是一种用于声明的关键字。定义在类声明之中的成员函数将自动地成为内联函数class A {原创 2023-07-21 22:00:06 · 108 阅读 · 0 评论 -
C++回调函数、静态函数、成员函数
随后需要运行回调函数的时候,使用一个辅助变量来运行,格式为:(变量名. * 函数指针)(参数)。若不想使用C式函数作为回调函数呢?原创 2023-07-21 21:48:51 · 380 阅读 · 0 评论 -
C++ STL sort函数的底层实现
其中先讲下快排和堆排,快排的平均复杂度为nlogn,但是它的复杂度是根据基准值来决定的,基准值选择的不好,最坏的复杂度会达到n2,而堆排序的复杂度是一定的为n*logn,那为什么不直接使用堆排序呢,是因为在将堆顶值与最后一个结点值交换并移除最后一个值后,在重新建堆的过程中,交换到堆顶的值显然比每个结点要小,但还是要经过对比判断,这个判断其实是多余的,因此这是它相比快排较慢的原因。于是,内省式排序结合了快排和堆排的特点,当快速排序到大一定深度(2logn)时,采用堆排序,以维持n*logn的复杂度。原创 2023-07-21 21:44:58 · 633 阅读 · 0 评论 -
C语言 strcpy,memcpy,memset,strcmp,memcmp
:把src所指由’\0’结束的字符串复制到dest所指的数组中。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。此小例子中,char c[]={‘i’,’ ‘,‘a’,‘m’,’ ‘,‘t’,‘e’,‘a’,‘c’,‘h’,‘e’,‘r’,’\0’};字符串一般默认后面有一个结束符,当用到strcpy(a,c);函数时,把c中的字符串复制到a中,当遇到字符串中默认的结束符后,复制结束。原创 2023-07-21 00:02:21 · 78 阅读 · 0 评论 -
C++ rand的用法
功能 : 随机数发生器用法 : int rand(void) 所在头文件 : stdlib . hrand() 的内部实现是用线性同余法做的,它不是真的随机数,因其周期特别长,故在一定的范围里可看成是随机的。rand() 返回一随机数值的范围在 0 至 RAND_MAX 间。RAND_MAX 的范围最少是在 32767 之间(int)。用 unsigned int 双字节是 65535,四字节是 4294967295 的整数范围。0~RAND_MAX 每个数字被选中的机率是相同的。原创 2023-07-20 23:49:18 · 594 阅读 · 0 评论 -
C++ bind function
std::bind定义在头文件functional里。以及其它函数对象。参数__args表示要绑定的参数列表。未绑定参数使用命名空间 std::placeholders 的占位符 _1, _2, _3等替换。原创 2023-07-19 23:01:58 · 65 阅读 · 0 评论 -
C++枚举类型
enum < 类型名 > {< 枚举常量表 > };关键字enum——指明其后的标识符是一个枚举类型的名字。枚举常量表——由枚举常量构成。“枚举常量"或称"枚举成员”,是以标识符形式表示的整型量,表示枚举类型的取值。枚举常量表列出枚举类型的所有取值,各枚举常量之间以","间隔,且必须各不相同。取值类型与条件表达式相同。原创 2023-07-19 22:51:21 · 52 阅读 · 0 评论 -
C++ class和struct的区别
C++ 中保留了C语言的 struct 关键字,并且加以扩充。原创 2023-07-19 22:30:57 · 61 阅读 · 0 评论 -
C++ vector容器注意事项
根据查阅的资料显示,考虑可能产生的堆空间浪费,成倍增长倍数不能太大,使用较为广泛的扩容方式有两种,以2二倍的方式扩容,或者以1.5倍的方式扩容。以2倍的方式扩容,导致下一次申请的内存必然大于之前分配内存的总和,导致之前分配的内存不能再被使用,所以最好倍增长因子设置为(1,2)之间,即:用一张图来说明2倍扩容与1.5倍扩容的区别:使用2倍(k=2)扩容机制扩容时,每次扩容后的新内存大小必定大于前面的总和。而使用1.5倍(k=1.5)扩容时,在几次扩展以后,可以重用之前的内存空间了。原创 2023-07-19 00:04:56 · 687 阅读 · 0 评论 -
C++emplace_back()和push_back()的区别
vector中可以用来从容器末尾添加元素的函数有 2 个,分别是 push_back() 和 emplace_back() 函数。1 2emplace_back()函数是 C++ 11 新增加的,其功能和 push_back() 相同,都是在 vector 容器的尾部添加一个元素。1 2emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。。原创 2023-07-19 00:04:43 · 240 阅读 · 0 评论 -
vector和list的区别
vector拥有一段连续的内存空间,并且起始地址不变。因此,它能够高效地进行随机存取,时间复杂度是O(1)。但是,因为其内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,因此时间复杂度为O(n)。另外,当数组内存空间不够时,会重新申请一块内存空间并进行内存拷贝。list是由双向链表实现的,因此内存空间是不连续的。其只能通过指针访问数据,所以list的随机存取效率很低,时间复杂度为O(n)。不过由于链表自身的特点,能够进行高效的插入和删除。原创 2023-07-18 23:35:09 · 93 阅读 · 0 评论 -
C++ deque/queue/stack的底层原理
和 vector 容器采用连续的线性空间不同,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。deque采用一块所谓的map数组(注意,不是STL的map容器)作为主控。(类似于vector),其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。SGI STL 允许我们指定缓冲区大小,默认值0表示将使用512 bytes 缓冲区。原创 2023-07-18 23:32:05 · 631 阅读 · 0 评论 -
C++ 优先队列 priority_queue
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。//对于基础类型 默认是大顶堆,等同于 priority_queue<int, vector<int>, less<int> > a;原创 2023-07-12 19:26:58 · 290 阅读 · 0 评论 -
C++ List容器的底层实现
和 array、vector 这些容器迭代器的实现方式不同,由于 list 容器的元素并不是连续存储的,所以该容器迭代器中,必须包含一个可以指向 list 容器的指针,并且该指针还可以借助重载的 *、++、–、==、!可以看到,list 容器定义的每个节点中,都包含 *prev、*next 和 myval。注:不同于双向循环链表,使用双向链表实现的 list 容器,其内部通常包含 2 个指针,并分别指向链表中头部的空白节点和尾部的空白节点(也就是说,其包含 2 个空白节点)。原创 2023-07-12 19:20:34 · 453 阅读 · 0 评论 -
C++ string详解
/把[first0,last0)之间的部分替换为s的前n个字符。原创 2023-07-12 19:09:01 · 328 阅读 · 0 评论 -
C++ unordered_map和map对比
map: unordered_map:map:map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树(又名二叉查找树、二叉排序树,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)存储的,使用中序遍历可将键值按照从原创 2023-07-11 20:32:15 · 571 阅读 · 0 评论 -
STL set容器
如果要将自定义的类型放入到set中的话,就需要重载“<”符号,原因是set是一个有序的集合,集合会按照“<”比较的大小,默认按照从小到大的顺序排列。public :为了让MyType类型可以顺利的放进set中,我必须重载“<”,这时问题来了,要如何重载呢?这个类型有三个数据成员,我能不能要求按照a的大小排列,如果a相等的话就随便按照b或者c的大小排列呢?原创 2023-07-11 19:53:02 · 188 阅读 · 0 评论 -
C++ union联合体
因为共用体将一个char类型的mark、一个long类型的num变量和一个float类型的score变量存放在同一个地址开始的内存单元中,而char类型和long类型所占的内存字节数是不一样的,但是在union中都是从同一个地址存放的,也就是使用的覆盖技术,这三个变量互相覆盖,而这种使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。由于a的存储区有好几种类型,分别占不同长度的存储区,仅写共用体变量名a,这样使编译器无法确定究竟输出的哪一个成员的值。原创 2023-07-11 19:27:40 · 326 阅读 · 0 评论 -
C和C++的区别
因此,C与C++的最大区别在于,它们用于解决问题的思想方法不一样。而在C++中的C,相对于原来的C还有所加强,引入了重载、内联函数、异常处理等。在C++中,不仅需要考虑数据封装,还需要考虑对象的粒度的选择、对象接口的设计和继承、组合与继承的使用等问题。C程序的设计首要考虑的是如何通过一个过程,对输入进行运算处理,得到输出。C++是面向对象的,C++程序的设计首要考虑的是如何构造一个对象模型,让这个模型能够配合对应的问题,这样就可以通过获取对象的状态信息得到输出或实现过程控制。原创 2023-07-11 19:23:19 · 53 阅读 · 0 评论 -
C++中可变参数宏
vsnprintf() 函数将格式化字符串fmt 指向的字符串写入字符串缓冲区buffer,可写入的最大字符数为 buf_size ,写入字符后,添加终止空字符;如果buf_size 等于零,则不写入任何内容并且buffer 可能是空指针。创建一个va_list类型的变量args,此时 args 还未初始化,类似一个空指针,接下来我们要把这个‘’空指针‘’ 指定到我们需要的位置上,比如指到fmt后。调用 va_start() ,args指向了fmt之后的参数,接下来就可以用args访问这些参数了。原创 2023-07-08 14:40:18 · 629 阅读 · 0 评论 -
GIT 简单命令
当远程仓库被更新过,应先。原创 2023-07-03 20:15:09 · 201 阅读 · 0 评论 -
进程和线程的区别
与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。原创 2023-06-08 21:02:54 · 47 阅读 · 0 评论 -
使用锁和条件变量实现生产者消费者
假设有一个或多个生产者线程和一个或多个消费者线程。生产者把生成的数据项放入缓冲区;消费者从缓冲区取走数据项,以某种方式消费。很多实际的系统中都会有这种场景。例如,在多线程的网络服务器中,一个生产者将HTTP 请求放入工作队列(即有界缓冲区),消费线程从队列中取走请求并处理。因为有界缓冲区是共享资源,所以我们必须通过同步机制来访问它,以免产生竞态条件。原创 2023-03-25 15:40:52 · 115 阅读 · 0 评论 -
多线程编程函数的使用
头文件。原创 2023-03-24 11:39:12 · 103 阅读 · 0 评论 -
GIT 使用简明教程
GIT 使用简明教程git的安装GIT 常用命令git的安装在 Windows 下, GIT 名为 msysGit,从 https://gitforwindows.org/ 上下载安装文件,双击安装即可。在 Ubuntu 下,执行以下命令即可,它会从网上下载安装 git。$ sudo apt-get install git对于 Windows 或 Linux,它们的命令行用法相似, 对于 Windows,进入 Git 命令行的方法是在“ 开始” ->“ 所有程序” ->“Git” 下原创 2023-02-18 19:48:26 · 351 阅读 · 0 评论 -
Makefile简单使用
Makefile简单使用原创 2021-08-13 10:39:15 · 1044 阅读 · 1 评论 -
函数指针解析
函数指针函数指针的定义及如何初始化函数指针应用函数指针的定义及如何初始化函数指针函数指针指的是函数而非对象。和其他指针一样,函数指针指向某种特定类型。函数的类型由它的返回值和形参类型共同决定,与函数名无关。int add(int i,int j){ return i+j;}int (*pf)(int,int);pf=add;pf=&add;//取地址符加不加,效果是一样的int add_value = pf(1,2);//调用add函数int add_value = (*pf原创 2021-10-30 20:59:41 · 116 阅读 · 1 评论 -
使用函数交换两个指针
这里写目录标题传指针但没有解引用传指针且解引用传指针但没有解引用void swap_pointer1(int *p1,int *p2){ int *p=p1; p1=p2; p2=p;}调用此函数,发现值并没有被交换。调用了swap_pointer1函数,还是没有改变它们的值,又是为什么呢?因为当我们把num1,num2的地址传进去的时候,指针变量*p1,*p2 就保存了主函数num1,num2的地址,但是p1和p2也只是一个临时变量。虽然在子函数把地址互相交换了,在返原创 2021-10-30 10:52:27 · 1835 阅读 · 1 评论