1. C++的内存管理分哪些区,分别有什么作用
C++的内存主要分为五大区:堆区、栈区、自由存储区、全局/静态存储区、常量存储区。
堆区:程序员分配释放,使用new分配内存块,使用delete归还内存空间。
栈区:编译器自动分配释放,用于存放局部变量、函数参数等。
自由存储区:程序员分配释放,使用malloc分配内存块,使用free归还内存空间。
全局区/静态区:全局变量和静态变量分配在同一块内存中。
常量存储区:存放不可修改的常量值。
2. C++源文本到可执行文件需要经历哪些阶段
预处理:将源代码和相关头文件处理成一个.i文件。
编译:将预处理的文件进行词法分析、语义分析,优化后产生相应的汇编代码。
汇编:将汇编语言代码翻译成目标机器码。
链接:把每个机器码文件按照要求连接起来,解决代码间的相互依赖问题。
3. 析构函数为什么必须是虚函数
为了保证整个派生类的对象完全被释放。
当析构函数不为虚函数时,在删除基类指针时,只会调用基类析构函数,而不调用派生类的析构函数,这样会导致基类指针指向的派生类对象析构不完全。
当析构函数为虚函数时,在删除基类指针时,会调用该指针指向派生类的析构函数,同时派生类的析构函数自动调用基类析构函数,保证对象被完全释放。
4. 虚函数和纯虚函数有什么区别
虚函数:在基类中存在定义,可以直接使用,也可以被派生类重写后使用。
纯虚函数:在基类中不存在定义,只有声明,必须在子类中定义后才能使用。
5. 虚函数的实现机制
编译器自动为存在虚函数的类生成一个虚函数表,当声明该类的对象时,放入一个隐式指针变量,指向虚函数表。
在调用方法时,系统根据不同对象的指针,寻找到对应的虚函数表,进而找到所需的函数地址进行调用。
6.野指针怎么出现的
指针变量未初始化。
指针释放后未置空。
返回指向栈内存的指针。
7. 类和结构体有什么区别
class中默认成员访问权限为private,而struct中为public。
class可以用于表示模板类型,sruct不行。
class是引用类型,struct是值类型。
class多用来存储数据量大、逻辑复杂的对象,struct多用来存储轻量级对象。
class多用于表现抽象和多级别的对象层次。
8. 什么情况会导致内存泄漏
程序循环new创建出来的对象没有及时delete掉。
delete掉一个void*类型的指针,导致没有调用到对象的析构函数。
new创建了一组对象,回收时未调用delete[],而调用了delete,导致只有对象数组的第一个对象的析构函数得到执行并回收了内存。
9. 五种IO模型
阻塞IO:进程发起IO系统调用后,进程被阻塞,转到内核空间处理,处理完毕后返回进程。
非阻塞IO:进程发起IO系统调用后,如果内核缓冲区没有数据,返回给进程一个错误,而不会阻塞进程,如果缓冲区有数据,则将数据返回给进程。【发起IO后,内核便开始处理,一直有返回值,但是直到内核处理完才有数据。】
IO复用:多个进程的IO注册到一个复用器(select)上,select监听所有进来的IO。【同时负责很多水龙头,哪个水龙头要来水了,就打开哪一个。】
信号驱动IO:进程发起IO系统调用后,向内核注册信号处理函数,然后进程返回不阻塞,当内核数据就绪则通知进程发起IO调用读取数据。【首先用信号通知内核空间,等到数据就绪再发起IO。】
异步IO:进程发起IO系统调用后,进程返回不阻塞,等内核将IO处理完,通知进程数据结果。
10. TCP如何保证传输的可靠性
校验和:接收方和发送方均进行校验和的计算,并进行对比。
序列号:TCP传输时将每个字节的数据都进行编号。
确认应答:TCP传输过程中,每次接收方收到数据后,均对传输方进行确认应答(ACK)。
超时重传:发送方在发送完数据后进行等待,一段时间后没有收到ACK,则对刚才的数据进行重新发送。
连接管理:三次握手与四次挥手。
流量控制:在回复ACK时,接收端介绍自己接受数据的缓冲区剩余大小。
拥塞控制:慢开始、拥塞避免等操作。
11. TCP快速重传的实现
举例:发送方发出1、2、3、4、5五份数据,1送到了,则回复ACK2,但是2没送到,3送到了,于是继续回复ACK2,后面4和5都送到了,继续回复ACK2,直到发送端收到三次ACK2,则重新发送2,然后接收端收到2,因为3、4、5都已经收到,所以回复ACK6。