ipv4和ipv6的区别?
1.在表现形式上
ipv4是32位,共有2的32次方个数字,ipv6则有128位。
ipv4基本表示时每个位都是10进制,ipv6每个位都是16进制。
IPv4协议的地址可以通过手动或DHCP配置的。
3.数据包的字节数不同。iPV6地址分配遵循Aggregation原则,路由器的路由表长度减少,提高转发数据包的速度。
4.在IPv6协议,地址解析协议(ARP)被邻居发现协议(NDP)的功能所取代。
5.IPv6提供身份验证和加密,但IPv4不提供。

参考链接:ipv4和ipv6的区别?

堆和栈的区别?(频率超高)

(1)管理方式不同。栈由操作系统自动分配释放;堆的申请和释放工作由程序员控制;(操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序。)
(2)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。
(3)存放内容不同。栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存.堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。

(4)空间大小不同。每个进程拥有的**栈的大小要远远小于堆的大小。**理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;

(5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。

(5)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca函数进行分配(alloca() 不具可移植性, 而且在没有传统堆栈的机器上很难实现。 所以没有普及),但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放,无需我们手工实现。

堆栈空间大小是由什么决定的?

栈空间大小:
是根据参数和局部变量估计一个大小足够容纳活动记录的空间,因此为不同函数分配的栈空间也是不同的编译器默认栈大小设置的是所有函数占用栈空间的上限,不管是一个函数还是多个函数超过这个总数就会报告栈溢出。没有哪个傻子写的编译器傻到为每个函数分配固定的栈空间去浪费内存,那样的话写一个简单的递归就会溢出,同样在函数中定义一个大一点的数组也会溢出。

堆空间大小
手动申请释放,堆内存的大小受限于计算机系统中有效的虚拟内存。

为什么栈空间相比于堆很小?
1.C的栈在x86-64上是直接绑定到CPU指令的,实现上极其精简,因此它与堆不同,没有动态增长、动态缩小的功能,**一旦分配出来就会永远占用相应的空间。**每个线程都会占用独立的栈空间,这样对于线程数很多的进程来说,如果栈空间分配得过多,就会很浪费内存空间。相反,**堆空间可以一开始分配得很小,然后不停向上增长,释放相应的空间之后还可以归还给操作系统,因此适合处理比较大的空间。**对于一定要占用比较大的栈空间的情况,可以指定栈空间大小。
2.堆通常是进程内共用的,栈通常是线程独占的,一个进程包含多个线程,所以堆就有必要比栈大了。

Linux默认的用户栈空间的大小是8MB(软限制)

为什么经常听到栈溢出,却很少听到堆溢出?

堆溢出:不断的new 一个对象,一直创建新的对象。(堆溢出不了,当你申请访问超过的大小的时候会返回失败。)
栈溢出:死循环或者是递归太深,递归的原因,可能太大,也可能没有终止。
栈溢出实例:
int f(int x)
{
int a[10];
a[11] = x;
}

因为栈空间分配是系统自动分配的,例如当发生递归的时候,栈中存放的数据放过了系统分配的栈空间大小,就会发生溢出。而首先堆的空间远大于栈,其次堆一般是我们手动申请释放,一旦申请超出范围就会报错。

进程线程和协程的区别?(被问频率超高)

1.进程是资源分配的最小单位。 线程是CPU调度的基本单位。
2.进程拥有独立的内存单元。同一进程下的多个线程共享内存。线程只独享指令流执行的必要资源,如寄存器和栈。
3.进程间不会相互影响,多考虑通信。线程间会相互影响,多考虑同步,通信可不通过内核直接通信。
4.进程编程调试简单可靠性高,但是创建销毁切换开销大。线程正相反,开销小,切换速度快,但是编程调试相对复杂。

用户态和内核态有哪些交互方式?如何共享内存的?

内核到用户:printk函数,文件
用户态到内核态: 在linux中,用户对设备的操作往往被抽象为对文件的操作。利用这一特性,可以通过注册和实现伪字符设备到内核,来实现用户进程和内核空间的交互。
内核态和用户态相互通信:
(1)proc文件系统,是当前内核或内核模块,和用户交互的主要方式。
(2)netlink是一种特殊的socket,用于用户态与内核态的双向通讯。

参考链接:https://blog.csdn.net/LinSeeker85/article/details/86599507

tcp如果设置非保活机制(关闭keepAlive),如果客户端和服务器端一直没有数据发送,该链接还存在么?
还存在。
要区别TCP的keepAlive和http的keep-Alive.
参考链接:tcp链接

暂时未解决的
1.乐观锁和悲观锁?
这个是数据库的知识,暂时看不懂
https://www.cnblogs.com/qlqwjy/p/7798266.html

聪聪面经
1、多态机制
多态就是说同一个名字的函数可以有多种不同的功能。分为编译时的多态和运行时的多态。编译时的多态就是函数重载,包括运算符重载,编译时根据实参确定调用哪个函数。运行时的多态则和虚函数、继承有关。

2、那多态底层实现是怎么样的
利用虚函数表,先构建一个基类,然后在基类的构造函数中会建立虚函数表,也就是一个储存虚函数地址的数组,内存地址的前四个字节保存指向虚函数表的指针,然后当多个子类继承父类之后,主函数中可以通过父类指针调用子类的继承函数。
那子类的多态函数是怎么被调用的?
因为每个子类都继承并设置了自己的虚函数表,每次用用父类指针创建新子类时就会出现,从而最终调用自己的表。
3、构造函数可以是虚函数吗?为什么?
不可以,因为虚函数存在的主要目的就是为了多态。而子类并不继承父类的构造函数,构造函数是创建对象时自己主动调用的,不可能被继承,所以没有使父类构造函数变成虚函数的必要。另外,父类在构造函数中创建虚函数表,实例化类对象,如果构造函数成为虚函数,那么因为类对象没有实例化导致不可能后续出现虚函数。
4、析构函数呢?!!!!
当析构函数是非虚函数时,主函数通过指针访问非虚函数时,编译器会根据指针的类型来确定要调用的函数;而指针是父类指针,所以调用父类的析构函数。
析构函数必须是虚函数。因为如果不是虚函数,当在主函数中用父类的指针new出一个子类对象,最后析构的时候,只会调用父类析构函数而不会调用子类析构函数。而且如果不为虚函数,父类指针就不会调用子类成员函数。
父类析构函数成为虚函数时,子类的析构函数会自动也变为虚函数。这个时候编译器会忽略指针的类型,而根据指针的指向来选择函数;也就是说,指针指向哪个类的对象就调用哪个类的函数。pb、pd 都指向了派生类的对象,所以会调用派生类的析构函数,继而再调用基类的析构函数。

5、如果析构函数不是虚函数,一定会出现内存泄露吗?
不一定,如果父类的变量里面没有指针,没有开辟空间,都是普通的变量,就不会出现内存泄漏。
6、指针和引用的区别!!!!
(1) 引用必须定义时初始化,不能像指针一样仅int a;这样定义,必须int & b=a;
(2) int & const r = a;这样写错误,因为引用本身就不能改变指向,添加const多此一举。
(3) 指针可以有多级但引用只能有一级。有int ** ,但是没有int &&.
(4) 指针的++,–代表下一个数据,引用的++,–代表数据本身的加减。
题外话:引用的本质就是指针,它的出现是为了书写方便,不要动不动有
,int a=10;
int &b=a; 这里&a,&b取址相同,并不代表引用b不占用内存,而是系统自动将&b转换成对b中内容的读取。而b里面保存的是a的地址。后台实际运行时int b=&a; b=12就是b=12。

7、用过哪些标准模板库(STL)
String类,迭代器,vector, deque, list, map, set等。
8、说一下vector的扩容机制
Vector扩容就是重新申请一段更长的内存空间并把以前的数据移动过去,释放以前的内存空间。以前的迭代器都会失效。一般用VS扩容都是扩容现有容器容量的50%。
9、说一说Map的底层实现
Map底层用红黑树。
红黑树是为了弥补二分查找树多次单边插入导致不平衡而引入的解决办法。
红黑树特点:

  1. 根节点和叶子节点(都是空节点)都是黑色。
    2.每个红色节点的两个子节点都是黑色。
    3.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

每次插入和删除都通过变色和旋转来保证红黑树符合上面的规则。

10、为什么map底层要用红黑树实现而不用AVL实现
平衡性方面(查找效率), 插入节点方面,删除节点方面。
因为avl树是高度平衡,而红黑树通过增加节点颜色从而实现部分平衡,这就导致,插入节点两者都可以最多两次实现复衡,而删除节点,红黑树最多三次旋转即可实现复衡,旋转的量级是O(1),而avl树需要维护从被删除节点到根节点这几个节点的平衡,旋转的量级是O(logn),所以红黑树效率更高,开销更小,但是因为红黑树是非严格平衡,所以它的查找效率比avl树低

RB-Tree是功能、性能、空间开销的折中结果。
总结:实际应用中,若搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB。

11、说一下你用过哪些C++11新特性!!!!

  1. 右值引用,移动语义(移动构造函数),完美转发。
    移动构造函数要解决地问题是:当使用深拷贝时,其中需要指针开辟非常多的空间,就会极大影响运行效率,这时通过避免不断拷贝,直接移植来解决问题。
    完美转发就是通过右值引用,让函数参数既可以接收左值又可以接收右值,同时保证函数中的形参可以同时保留原左右值属性而不改变。
  2. 智能指针。
  3. lambda 匿名函数。
    12、智能指针有几种?分别介绍一下他们的底层实现
    Share_ptr, unique_ptr, weak_ptr。
    13、它们三者有什么区别
    shared_ptr,unique_ptr,weak_ptr。第一个实现原理是同一个内存空间每多一个指针指向就计数加1,如果计数变为0就释放内存空间。第二个是计数只能为1,第三个只能指向该内存空间而没有所有权。主要用于辅助第一个指针,防止出现互锁。Shared_ptr当用普通指针初始化的时候,只能使用一次普通指针。它还可以自定义释放函数。Unique_ptr没有拷贝构造函数。借助 weak_ptr 类型指针, 我们可以获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、shared_ptr 指针指向的堆内存是否已经被释放等等。在构建 weak_ptr 指针对象时,可经常利用已有的 shared_ptr 指针为其初始化。
    1、为什么需要智能指针?它在实际工程中有什么作用
    为了防止内存泄漏,设置的自动回收机制。
    2、说一下shared_ptr的底层实现?
    引用计数,每多一个智能指向同一个内存,就把计数加1,当计数减到0的时候就释放该指针。当该指针作为形参传递的时候,计数会加1,当他出该函数时会自动减一。
    3、Weak_ptr的作用?
    获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、shared_ptr 指针指向的堆内存是否已经被释放等等。另外防止循环引用。
    4、你刚才说到循环引用,那你口述一个循环引用的实例。
    比如说A、B两个类,两个类里面分别定义了一个对方类的智能指针,然后在主函数里面首先定义两个类的智能指针,然后分别把两个指针分别赋予对方的成员指针里,这样就形成了循环引用。
    循环引用的问题是:一旦b出作用域,引用计数减一,导致b里面的a永远不会减一,导致a智能指针空间永远释放不掉,然后a出作用域时,a引用计数减一,a最终没释放,它里面的b也就不可能释放掉,最后a b都是1无法释放。
    5、在你说的这个实例中,那你怎么用weak_ptr来解决呢?
    把两个类里的智能指针定义为weak_ptr指针,这样第二次赋值的时候引用计数就不会加1,这样两个就不会相互影响了。

14、说一下lambda表达式的底层实现
相当于调用了类,在类里对()进行了重写。当需要捕获变量的时候,就以成员函数的形式保存需要捕获的变量。
https://www.cnblogs.com/diegodu/p/9377438.html

15、怎么实现让udp可靠
在应用层
1、添加seq/ack机制,确保数据发送到对端
2、添加发送和接收缓冲区,主要是用户超时重传。
3、添加超时重传机制。
详细说明:送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。
现有的机制有RUDP、RTP、UDT
16、http与https的区别
https=http+TLS/SSL协议,安装SSL证书后,使用https加密协议访问网站,可激活客户端浏览器到网站服务器之间的"SSL加密通道"(SSL协议),实现高强度双向加密传输,防止传输数据被泄露或篡改。
17、tcp粘包现象
tcp发送数据是基于字节流发送的,即发送端执行多次写操作之后,tcp系统先把数据保存在写缓冲区,真正发送的时候封装成一个一个包发出去,发送方发送的若干包数据到达接收方时粘成了一包。导致一个包里面出现不同类型或者不是同一批的数据,就会出现粘包。
18、怎么解决粘包现象
对于发送方可以关闭优化算法,强制立即发送。对于接收方不能改变,但是可以改变应用层的处理方式,格式化每个包的数据格式,给每个包中都用前几个字节保存包的长度
19、你的项目中为什么选择epoll
每次不用遍历注册表,就绪的事件会自动存储在数组中。
能够就绪的文件描述符没有最大数量限制。
支持ET、LT两种模式。(这个是重点)
缺点:系统开销大,不能跨平台。
20、说一下epoll、select、poll区别,那他们的底层实现能说一下吗?
select使用线性表描述文件描述符集合,文件描述符有上限;poll使用链表来描述;epoll底层通过红黑树来描述,并且维护一个ready list,将事件表中已经就绪的事件添加到这里,在使用epoll_wait调用时,仅观察这个list中有没有数据即可。
21、描述一下虚拟内存!!!!
最开始的时候,程序运行就是直接放进内存的,但是内存空间有限,程序放的时候成块放,有时候会造成内存空间的浪费或者造成大量的内存碎片,于是决定在磁盘上找一个空间,用来扩大内存,磁盘这段空间就成为虚拟内存。光扩大内存还不行,必须要减少内存碎片,所以,将物理内存进行了分页,每一页大小相等,同时将虚拟内存也进行了分页。平时不需要的就放在磁盘中,需要运行的磁盘通过虚拟内存放到实际的主存中,这样就不害怕主存太满放不下了。虚拟内存存放在磁盘里,它里面包括不存在的,未映射的和已经映射的内存地址。但是如果分页太多的话,每次调用进程就会特别占空间,所以又在内存中划分出一块空间,作为一级页表,后续需要哪一个页,再调用对应的页表进行查询转换。页表中存放的是虚拟地址和物理地址的映射关系。mmu负责根据页表将虚拟地址转换为实际地址。TLB里面是高速缓存,每次映射前可以先从TLB中查找是否有想用的缓存,可以大大提高转换效率。页表中的有效位会判断是否物理地址是否为空。缺页时会从主存里面选择一个牺牲页,并把该牺牲页的内容拷回到磁盘里,然后用需要的地址取代它。
22、算法题:判断单向链表是否为回文链表
23、反问

二面
6、C++中三种权限的区别
Public:可以被任意成员函数访问。
Protect:可以被本类或者子类成员函数访问。
Private:只能被本类成员函数访问。
7、静态成员函数有哪些特性!!!!
可以说静态成员函数的出现就是为了处理静态成员变量的。静态成员变量。static成员变量属于类(被存放在数据段中),不属于某个具体的对象(具体对象的内存是分配在堆中的),即使创建多个对象,也只为该变量分配一次内存,所有对象使用的都是这份内存中的数据。
静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)另外相比普通成员函数,不管有没有创建对象,主函数都可以调用静态成员函数。
(1)静态成员函数只能访问静态成员变量。只能去调用其他静态成员函数。
(2)相比普通成员函数,不管有没有创建对象,主函数都可以调用静态成员函数。

8、静态成员函数可以设置为virtual吗?为什么?

  1. static成员不属于任何类对象或类实例,所以即使给此函数加上virutal也是没有任何意义的。

  2. 静态与非静态成员函数之间有一个主要的区别。那就是静态成员函数没有this指针。

    虚函数依靠vptr和vtable来处理。vptr是一个指针,在类的构造函数中创建生成,并且只能用this指针来访问它,因为它是类的一个成员,并且vptr指向保存虚函数地址的vtable.
    对于静态成员函数,它没有this指针,所以无法访问vptr. 这就是为何static函数不能为virtual
    9、虚函数表主要是用来干嘛的?
    是用来储存基类中的虚函数,主要用于多态。

10、你用过哪几种锁
互斥锁,读写锁:写独占,读共享,写锁优先级高。
文件锁(只能用于进程间)(黑马p214-215)

11、说一下互斥锁和读写锁的区别
读写锁比互斥锁有更高的并行性,一个线程被互斥锁加锁之后,其他的线程必须等该互斥锁解锁之后才能加锁,而读写锁的读模式可以允许多个线程同时进行读加锁。
12、为什么会发生死锁?你项目中发生死锁你是怎么解决的?
死锁发生时出现的四个条件:!!!!
互斥使用:一个进程加锁后占有资源,另一个进程就不能使用该资源。
不可抢占:一个进程不能强制剥夺另一个进程的未使用完资源。
占有并等待:一个进程因为请求资源而阻塞的时候,不能释放已有的资源。
循环等待:一个进程等待另一个进程资源的释放,另一个进程等待该资源的释放。
解决办法:破坏其中一个条件
第一个条件不太方便破坏。
破坏不可抢占:当某个线程拿到一部分资源之后,又去申请其他的资源,如果申请不到,主动释放占有的所有资源。
破坏占有且等待:每个请求者一次性申请所有需要的资源,如果无法申请就等待。
破环循环等待:给每个资源编号,先申请编号小的,再申请编号大的。
13、你会哪些死锁的排查手段?你是怎么知道你的项目发生死锁现象的
参考连接:https://blog.csdn.net/liaozhilong88/article/details/80354414
排查方法:在锁类中记录当前进程的ID以及希望请求的资源被占用的进程的ID。然后判断他们的进程ID是否形成一个循环来判断是否发生死锁。以及哪些进程造成了死锁。

14、说一下C++模板
函数模板template ,类模板template
15、Tcp、udp区别
16、知道哪些拥塞控制算法?
17、具体说一下快重传是怎么工作的?
18、滑动窗口

19、说一下你了解哪些容器
Vector,deque,list,map,unordered_map,unordered_set等。
vector的扩容机制重新寻找一段更大的连续内存,把上一个内存里的数据复制过来,释放以前的内存空间。以前的迭代器都会失效。一般用VS扩容都是扩容现有容器容量的50%。

20、你vector扩容后,在拷贝元素时有哪几种拷贝方式
List是已经定义了的vector类型
(1)vector tem(list);
(2)vector temlist;
temlist.assign(list.begin(), list.end());//assign代表用新元素替换原有内容。
(3)vector temlist;
temlist.swap(list);//swap代表交换两个容器的所有元素
(4)vector temlist;
vector temlist2;
temlist2.push_back(2);
temlist2.push_back(2);
temlist.insert(temlist.end(), temlist2.begin(), temlist2.end());//将temlist2中的数据,全部插入到temlist的末尾。相当于复制了一份数据。

21、说一下深浅拷贝
当类持有动态分配的内存、指向其他数据的指针等的时候,需要深拷贝,保证拷贝的类里的指针指向自己的空间。这样做的结果是,原有对象和新对象所持有的动态内存是相互独立的,更改一个对象的数据不会影响另外一个对象,
22、什么是抽象类
包含纯虚函数的类称为抽象类。
23、子类实现抽象类有哪些注意事项
必须把基类中的所有纯虚函数都初始化实例化。子类的函数名必须和抽象类一样,参数类型也要一模一样。

24、那基类的所有纯虚函数都要实现吗?
对,所有的都要实现。
25、抽象类存在的意义,要解决什么问题?
在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
在实际开发中,你可以定义一个抽象基类,只完成部分功能,未完成的功能交给派生类去实现(谁派生谁实现)。这部分未完成的功能,往往是基类不需要的,或者在基类中无法实现的。虽然抽象基类没有完成,但是却强制要求派生类完成,这就是抽象基类的“霸王条款”。

26、你的项目中用到哪些设计模式、
单例模式
27、懒汉模式和饿汉模式具体怎么实现
看书的最后一页。
单例模式要两次加锁的原因是,如果针对多线程,两个线程同时判断出指针为空,就会同时创建两个单例的指针,判断一次之后进行加锁后再创建实例,就可以避免有另一个同时判断成功也迅速创建了实例,因为加锁后另一个进程不能再进入。
28、单例模式会带来哪些问题?
单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
29、有用过动态规划来解决实际问题吗?说一下它的思想?
动态规划最初是为了解决递归重复计算导致超时的问题,后来为了防止多次重复计算,引入了记忆化递归,但是记忆化递归仍然效率不是特别高,在记忆化递归的基础上改进后,形成了自上而下的动态规划方法。
30、你web服务器能说一下项目框架吗?

31、线程池是自己实现的吗?
是。

32、那你说一下它的结构以及怎么工作的?
线程池最重要的是一个线程池数组和一个任务队列,在类的构造函数中创建一定数量的线程,并放到线程池数组中,然后主函数中将任务插入到请求队列中,已经创建的线程对队列中的任务进行抢夺,得到任务加锁进行处理,处理主要依靠线程的运行函数,该函数会调用http类里的解析函数对客户端的请求进行解析。并且调用数据库连接池导入数据。
为了可以同时处理多个连接,需要在让一个线程的处理函数不间断的进行while循环

33、项目里为什么要有recactor和proactor这两个模式?

34、状态机设计机制是什么?你使用状态机给你项目带来哪些好处?
(自己编的)状态机就是用于不同状态转换的一种数学模型。
设计机制:将程序中的不同状态进行整合,来保证不论状态发生的顺序如何,最后都能转移到需要的状态上。
好处:项目中状态机主要用于对客户端请求的处理,其中有三种状态,处理请求行,处理请求头,处理请求体,有了状态机,一方面可以避免多种状态同时发生造成混乱。另一方面保证了状态处理结束后能够正确的进行状态转移,相比只有if进行判断更加安全可靠。
35、有没有想过状态机会给项目带来哪些危害?
缺点:状态机的缺点就是性能比较低,一般一个状态做一个事情,性能比较差,在追求高性能的场景下一般不用,高性能场景一般使用流水线设计。
36、你在项目设计的过程中遇到过什么问题?是怎么解决的。
37、算法题:两个栈实现一个队列

1、 c++的空类会默认生成哪几个成员函数?!!!
参考链接:https://blog.csdn.net/taiyang1987912/article/details/43485569
对于空类,编译器不会生成任何的成员函数,只会生成1个字节的占位符。
有时可能会以为编译器会为空类生成默认构造函数等,事实上是不会的,编译器只会在需要的时候生成6个成员函数:一个缺省的构造函数、一个拷贝构造函数、一个析构函数、一个赋值运算符、一对取址运算符和一个this指针。
class Empty
{
public:
Empty(); // 缺省构造函数
Empty( const Empty& ); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=( const Empty& ); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};
默认构造函数
析构函数
拷贝构造函数
赋值运算符(operator=)
取址运算符(operator&)(一对,一个非const的,一个const的)
2、 拷贝构造函数了解过吗?属于深拷贝还是浅拷贝?
如果只是简单的数据复制就是浅拷贝,如果需要开辟新的空间,或者复制类的时候提前需要做一些准备,就需要深拷贝。
指针开辟空间的深拷贝:https://blog.csdn.net/joshgu958/article/details/35302413

3、 (拷贝)赋值函数是什么?
https://blog.csdn.net/weixin_43919932/article/details/88730884
4、 C++的多态是通过什么机制实现的?
虚函数表,C语言中文网pdf的5.5节。
比想象中的简单,就是内存中保存一个指针vfptr,该指针始终指向虚函数表(它本质就是个保存虚函数地址的数组)首地址,然后需要调用哪个虚函数,就在首地址上进行偏移。具体内容看PDF吧。
5、 构造函数可以是虚函数吗?为什么?
首先,虚函数的唯一存在的原因就是为了构成多态,但是派生类并不继承构造函数,构造函数是在创建对象时自己主动调用的,不可能通过子类的指针或者引用去调用继承。所以没必要(主要原因)。另一方面,构造函数为类对象初始化了内存空间,里面保存指向虚函数的指针vfptr,如果构造函数是虚函数,导致没有实例化类对象,也就没有内存空间,也就不可能有虚函数。
6、 虚函数的安全性有什么问题?
可以通过虚函数表,让父类指针访问子类的自有虚函数。这带来一定的安全问题。另外,即使父类的虚函数是私有函数或者保护函数,仍然可以通过虚函数表访问,带来一定的安全问题。
参考链接:https://coolshell.cn/articles/12165.html#%E5%AE%89%E5%85%A8%E6%80%A7
7、 智能指针了解吗?它们的实现原理是什么?
了解。有三种,shared_ptr,unique_ptr,weak_ptr。第一个实现原理是同一个内存空间每多一个指针指向就计数加1,如果计数变为0就释放改指针。第二个是计数只能为1,第三个只能指向该内存空间而没有所有权。主要用于辅助第一个指针,防止出现互锁。

8、 写时拷贝有了解过吗?
和移动语义很像,都为了解决深拷贝带来的问题,移动语义是为了解决深拷贝时多次拷贝导致多次开辟空间降低运行效率产生的,而写时拷贝是读取的时候不会进行深拷贝,只有你写的时候才会拷贝,是拖延版深拷贝。String类里面就有所运用。不深拷贝仅仅让多个指针指向同一个空间,然后每次进行计数。
具体可参考这个:https://blog.csdn.net/Dawn_sf/article/details/66522352

9、 迭代器的内部是怎么实现的?
链接如下,暂时看不懂
https://blog.csdn.net/lpstudy/article/details/80281769
10、 死锁的原因?
Ok
11、 fork出来的子进程和父进程有什么区别?
Fork返回值不同,父进程返回值大于0,子进程等于0。进程ID不同。子进程需要回收。 否则变成僵尸进程。
fork()使用了写时复制的方法,减少了创建进程的内存开销。写时复制表示fork的子进程和父进程共享同一份资源,只有其中一个进程发生写事件时,才会复制资源。
vfork()也是用于创建进程的,与fork()不同的是,vfork()创建子进程后,除非子进程结束,否则父进程不能运行。
13、冒泡排序和快排的时间复杂度?
14、TCP三次握手和四次挥手?
Ok.
15、UDP怎么实现可靠传输?
在应用层
1、添加seq/ack机制,确保数据发送到对端
2、添加发送和接收缓冲区,主要是用户超时重传。
3、添加超时重传机制。
详细说明:送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。
16、TCP怎么实现流量控制(发送端和接收端分别阐述)?
拥塞避免

超盛面经
3、线程同步的方式:
POSIX信号量,互斥锁,条件变量。
5、线程数据如何同步?ok
6、项目除了互斥锁?还用过什么锁?
答:项目只用了互斥锁,没用过其他锁
7、互斥锁与读写锁区别?ok
9、线程数量根据什么考虑?ok
CPU密集型任务:一般配置线程数=CPU总核心数+1
IO密集型任务:一般配置线程数=CPU总核心数 * 2 +1

10:除了半同步/半反应堆模式?还用过什么模式?ok
答:领导者追随者模式,但用的不多。
13:ET、LT优缺点?
ET模式
缺点:应用层业务逻辑复杂,容易遗漏事件,很难用好。
优点:相对LT模式效率比较高。一触发立即处理事件。
LT模式:
优点:编程更符合用户直觉,业务层逻辑更简单。
缺点:效率比ET低。

14:什么时候用ET,什么时候用LT?
LT适用于并发量小的情况,ET适用于并发量大的情况。
15:怎么解决LT的缺点?
LT模式下,可写状态的fd会一直触发事件,该怎么处理这个问题
方法1:每次要写数据时,将fd绑定EPOLLOUT事件,写完后将fd同EPOLLOUT从epoll中移除。
方法2:方法一中每次写数据都要操作epoll。如果数据量很少,socket很容易将数据发送出去。可以考虑改成:数据量很少时直接send,数据量很多时在采用方法1.
16:触发LT模式后,读一次还是循环读?
读一次。
17:项目显示图片,有没有自己定义相关协议?
没有。
18:项目日志系统的工作流程?
日志分为同步日志和异步日志,异步日志利用阻塞队列,先将日志放入阻塞队列中,然后利用条件变量将日志添加到对应文件中。下面的意思是如果文件名没带路径,直接放到log_full_name。如果带路径,把文件名取出来放到log_name,把路径取出来放到dir_name,然后把时间+log_name放到log_full_name。这就是在初始化函数中主要要做的事。
在write_log()函数中,这里面有两部分,一部分是对新的文件名,时间,日志名进行再次处理,一部分是时间+新加入的日志参数放入缓冲区。异步加入阻塞队列,同步直接写入日志文件。阻塞队列是用数组模拟的生产者消费者模式。根据初始化函数传入的最后一个参数阻塞队列最大容纳值判断是同步还是异步,异步则其大于等于1。

19:请求视频或图片后,中途失败,怎么排查问题?
一般就会查看日志,看是查看是服务器端还是客户端导致的问题。
20:开发项目时,你如何调试?
21:项目运行时奔溃?你如何排除解决?
这些都是利用日志系统。
22:项目的多线程改成多进程,如何改?
使用for循环,每次都调用fork()创建6个子进程
23:管道能不能非父子通信?
可以,命名管道就是非父子通信。用int mkfifo(const char *name,mode_t mode)创建。第二个参数S_IFIFO|0666 指明创建一个有名管道且存取权限为0666,即创建者、与创建者同组的用户、其他用户对该有名管道的 访问权限 都是 可读可写。

24:还有哪些其他进程通信方式
互斥锁(把互斥锁初始化函数的属性由以前的空null改为进程间通信)。
文件锁(只能用于进程间)(黑马p214-215)
信号量,消息队列,共享内存
25:不同进程看共享内存,是不是看到同一个内存地址?
是。
利用mmap()函数创建一个映射区,映射区就是将磁盘上的一个文件,在内存中创建一,块区域进行映射,以后在这块内存区域进行读写,就相当于在磁盘的文件中进行读写。
Mmap()的第一个参数一般设置为空,代表系统会自动在内存中分配一块地址,第二个参数是分配地址的大小,第三个参数是这块内存的读写权限,第四个参数是设置磁盘文件和内存映射区当被修改时是否同步,第五个是磁盘文件的文件描述符,第六个是设置从磁盘文件的哪里开始映射,即偏移量。该函数返回一个内存指针,指向内存的映射首地址。失败返回一个宏。
映射结束后用munmap进行释放该内存,也就是借助这块映射内存往磁盘文件里写东西,写完就可以把它去掉,这时查看文件就会发现有内容。
注意:
映射文件大小不能为0,所以一定要设置文件大小。
内存映射区的权限要小于等于文件的权限,从创建内存映射区的过程中隐含一次对文件的读操作。不论内存和文件设置同步不同步。如果报错段错误,gdb [程序] 然后 run,就会跳到段错误的地方。
参数偏移量一定要是4k的整数倍。

综上,多进程第四个参数为MAP_SHARED表示,父子进程共享文件和内存映射区。MAP_PRIVATE表示不共享。

匿名映射,不需要创建文件了,第五个参数直接为-1,第四个参数或上MAP_ANON
26:电脑只有2GB物理内存,申请4GB数组,能不能成功?
可以,有虚拟内存
27:看过什么Liunx书籍?
《Linux高性能服务器编程》
28:TCP四次挥手过程状态变化?
客户端:E->FIN_WAIT1-> FIN_WAIT2->TIME_WAIT->CLOSE
服务器端:E->CLOSE_WAIT->LAST_ACK->CLOSE
29:time_wait作用?
这里同样是要考虑丢包的问题,如果第四次挥手的报文丢失,服务端没收到确认ack报文就会重发第三次挥手的报文,这样报文一去一回最长时间就是2MSL,所以需要等这么长时间来确认服务端确实已经收到了。
30:time_wait阶段,客户端发送ACK给服务端,但是服务端还没接收到,客户端下一步动作是什么?
超时重复发送
31:为什么是2MSL?怎么计算的?
2MSL就是一个发送和一个回复所需的最大时间。2MSL是两倍的MSL(Maximum Segment Lifetime)

32:两台机器没通信过,要通信,要用什么协议?
Tcp/IP协议
33:构建一个IP包,是由什么决定IP包发送到哪里去的?
DNS查找的目标IP地址。
34:ARP协议是什么?
主要用于利用目标IP地址广播帮助找到要转发的MAC地址。
35:ARP协议的结构是什么?
后20个字节分别是发送端和接收端的IP地址和MAC地址。前几个是硬件类型(1为MAC地址)和协议类型以及他们的长度,还有ARP执行的操作(请求或应答)。
36:粘包和半包了解过吗?
了解过。
37:什么是粘包?
发送的包粘在一起。
38:怎么解决粘包这个问题?
格式化数据,或者首部添加数据长度信息。
39:C++11了解过什么
答:智能指针,移动构造,右值
40:什么是右值引用?
分为右值和引用,引用就是给变量换一个名字,它的底层仍然是指针,只不过经过包装没有取值符更加简洁方便,右值一般来说在等式右边的值就是右值,右值一般没有名字,没有地址。右值的引用的形式即int && a; 实际开发中我们可能需要对右值进行修改。
41:多态实现?
基类定义虚函数,在子类中对虚函数进行重写。
42:怎么知道多态时,指向哪个虚函数?
定义的父类指针new出哪个子类就是指向哪个子类的虚函数。
43:对象怎么找到对应的虚函数表?
( *( (p+0) + 0 ) )§; p是父类指针,p+0是指针vfptr,该指针指向虚函数表的首地址。所以(p+0)即虚函数表的地址,( *(p+0) + 0 )就是要找的虚函数的地址,+0代表该虚函数在表中的偏移量。( *( *(p+0) + 0 ) )§表示对该函数的调用。

44:A,B两个类,类中有虚函数。C继承AB,有几张虚函数表?
答:2张
再问:为什么2张?
多继承就会有多个虚函数表。因为每个父类的虚函数是不同的,指针也是不同的。
如果共用一张虚函数表,就分不清到底子类的实例化是针对哪一个基函数的。
45:介绍一下生产者消费者?
生产者和消费者主要用于对于数据的同步使用,生产者生产数据,然后放到共享缓冲区中,消费者在缓冲区没有数据之前会阻塞等待,当生产者生产数据之后,会用signal函数唤醒阻塞,开始消费数据,而当数据生产充满缓冲区之后,生产者就会阻塞等待。其中的阻塞都使用条件变量。
46:什么是迭代器失效?
就是比如vector容器扩容的时候,释放了原来的内存空间,导致原来的迭代器都失效不能用了。
迭代器失效就是因为扩容,删除元素等缘故,导致原先容器的空间变化,进而导致迭代器(begin()和end())发生了变化,从而失效。
47:vector内部实现?
Vector是一个类,它里面有三个指针myfirst,mylast,myend.分别表示首地址,元素容量地址,容器容量地址。通过这三个指针分别表示容器的所有操作。
48:vector.push_back()一个值,内部发生什么?
如果容量充足,就会在容器末尾添加该元素,如果容量不足,就会自动扩容,扩容的时候会重新寻找一个更大的连续内存,原来的迭代器会失效。扩容一般会扩大现有容器量的50%。
49:构造函数内能调用虚函数吗?为什么?
不能,…

Cvte二面
1.介绍一下你的项目
2.epoll说一下
3.为什么用epoll ok
4.select poll ok
5.在连接少但都比较活跃的情况下性能为什么要选select或者poll好一点(说底层)
因为这两个的文件描述符都是在用户态加入文件描述符集合的,相对于epoll每次都在内核态调用,即使都比较活跃也不会产生太大的系统开销,并且因为连接少遍历就绪文件描述符容易。
6.recactor和proactor事件处理模式知道么讲一下
7.为什么要有这两个模式
因为一个是同步IO模型建立的,一个异步IO建立,同步IO需要应用自行在应用程序里执行I/O操作,而异步IO都是内核帮助完成,更加方便快捷,但是设计机制仍然不太成熟。
8.recactor为什么主线程只负责监听而工作线程负责处理,为什么这样设计

9.两个线程可以同时对一个socket发送链接么、会有什么问题出现么
导致发生数据拥塞,
10.你的项目http请求怎么做的?如何保证http请求完整解析
11.如果我发的http包特别大怎么办
Tcp的时候会进行数据切片
12.粘包懂么,讲一下ok
13。Tcp udp讲一下ok
14.tcp为什么要切片 切片发生在哪里ok
15。udp会切片么ok
16.为什么tcp面向字节流,udp面向报文
17.你的项目如果发生粘包怎么办ok
18.临界区和互斥量区别是什么?能从底层说一下么

临界区主要针对线程。
互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享(注意是线程)。
互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使。所以创建互斥量需要的资源更多,所以如果只为了在进程内部使用的话,使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。
19.进程 线程ok
20.http 1.0 http2.0区别
HTTP2.0和HTTP1.X相比的新特性
• 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
• 多路复用(MultiPlexing),即连接共享,即每一个request都是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
• header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
• 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

21.多进程和多线程说一下各自应用场景
1.需要频繁创建销毁的优先使用线程。例如:web服务器,来一个建立一个线程,断了就销毁线程。要是用进程,创建和销毁的代价是很难承受的。
2.需要进行大量的计算优先使用线程。所谓大计算量,就是消耗CPU很多,切换频繁,这种情况用线程最合适。例如:图像处理,算法处理。
3.强相关处理用线程,弱相关处理用进程。一般的server需要完成的任务如下:消息接发和消息处理。接发消息和消息处理就是弱相关任务,而消息处理里面又能分为消息解码,业务处理,这两个任务相对来说相关性强很多,因此,消息接发和消息处理可以分进程设计,消息解码和业务处理可以分线程设计。
4.可能扩展到多机分布的用多进程,多核分布用多线程。

22.多线程一定比单线程好么?
不一定,因为多线程的上下文切换和线程创建所带来的开销会带来一定的消耗。
23.举一个实际场景来说明单线程有时候比多线程更优(单cpu情况下)
一个线程累加count,一个线程累减count;另一个在单线程中完成这两个。当count小于10万时,单线程更快,大于10万
https://blog.csdn.net/u013568373/article时多线程更快。/details/93488554
24.智能指针知道么?说一下ok

Webbench是什么,介绍一下原理
父进程fork若干个子进程,每个子进程在用户要求时间或默认的时间内对目标web循环发出实际访问请求,父子进程通过管道进行通信,子进程通过管道写端向父进程传递在若干次请求访问完毕后记录到的总信息,父进程通过管道读端读取子进程发来的相关信息,子进程在时间到后结束,父进程在所有子进程退出后统计并给用户显示最后的测试结果,然后退出。

网络各层校验用的什么? ARP协议?
tcp传输层的头部校验:https://www.jianshu.com/p/1b0ca8f5b2fc
IP层也是首部校验和
数据链路层:奇偶校验码(Parity Check Code,
PCC)、循环冗余校验(Cyclic Redundancy Check, CRC)两种

C++面经汇总(二)相关推荐

  1. 面试题汇总二 Java 多线程篇

    前言 题目汇总来源 史上最全各类面试题汇总,没有之一,不接受反驳 面试题汇总一 Java 语言基础篇 面试题汇总二 Java 多线程篇 面试题汇总三 Java 集合篇 面试题汇总四 JVM 篇 面试题 ...

  2. 神经网络与深度学习笔记汇总二

    神经网络与深度学习笔记汇总二 正交化(方便调整参数) 迭代 单实数评估指标(判断几种手段/方法哪个更好) 指标选取 训练集.开发集.测试集作用与用途 评估指标 判断算法是好是坏 迁移学习 总结 往期回 ...

  3. MySQL--经典题目综合汇总二(进阶)--建议先把之前的看了,难度较高

    MySQL--经典题目综合汇总二(进阶)--建议先把之前的看了,难度较高 1.表格创建 2.题目部分 题目一:求所有课程平均成绩排名在2到4名的同学信息(压轴) 题目二:查询不同老师所教不同课程平均分 ...

  4. 语音信号处理领域国内外大师汇总(二)

    语音信号处理领域国内外大师汇总(二)                              本内容由灵声讯音频-语音算法实验室整理,转载和使用请与"灵声讯"联系,联系方式:音频 ...

  5. Hibernate面试题经典汇总(二)

    Hibernate面试题经典汇总(二) 1.下面不属于持久化的是( a) A.把对象转换为字符串的形式通过网络传输,在另一端接收到这个字符串后能把 对象还原出来 B.把程序数据从数据库中读出来 C.从 ...

  6. 电赛汇总(二):常用传感器电路模块设计

    电赛汇总(二):常用传感器电路模块设计 这一章节主要详细记录各种常用的传感器的电子芯片型号.设计原理与思想,以便随时查看翻阅.这部分内容出自黄根春等学者著的<全国大学生电子设计竞赛教程–基于TI ...

  7. Java面试笔试题大汇总二(最全+详细答案)

    本篇文章内容过多,只能分成两部分: 汇总一:https://blog.csdn.net/qq_20757489/article/details/93714854 汇总二:https://blog.cs ...

  8. 潇的MySQL自学日记-汇总(二)

    这是对汇总(一)的进一步修改! -- 2021/6/14 START 目录 -- 第四章 检索数据 -- 第五章 排序检索数据 -- 第六章 过滤数据 -- 第七章 数据过滤 -- 第八章 用通配符进 ...

  9. iphone开发资源汇总(二)

    如何用Facebook graphic api上传视频: http://developers.facebook.com/blog/post/532/ Keychain保存数据封装: https://g ...

  10. EEG伪影详解和过滤工具的汇总(二)

    点击上面"脑机接口社区"关注我们 更多技术干货第一时间送达 在<EEG伪影类型详解和过滤工具的汇总(一)>,我们详细介绍了EEG伪影类型和产生原因,这篇文章,我们主要介 ...

最新文章

  1. ffmpeg 基本用法大全
  2. Linux下Apache虚拟主机配置
  3. XHProf报告字段含义
  4. mybatis+spring报错PropertyAccessException 1: org.springframework.beans.MethodInvocationException
  5. resnet系列+mobilenet v2+pytorch代码实现
  6. html 动物特效,分享9款用HTML5/CSS3制作的动物人物动画,
  7. Java 获取项目文件路径
  8. 控制台应用程序中Main函数的args参数
  9. python中pprint是干什么的_Python中的pprint折腾记
  10. 《云云众声》第101期:众家发声 追求“中国特色”
  11. 大学生心理健康管理系统
  12. GWAS meta分析
  13. 1G PHP免费空间
  14. Mapbox添加图片层
  15. GSM-GPRS-WCDMA-LTE-5g 的总结
  16. 网络原理 | 网络设备及相关技术(集线器、交换机、主机、路由器)、冲突域与广播域
  17. android文件目录
  18. java蘑菇岛种子_比蘑菇岛更稀有的“蘑菇陆地”见过么?输入MC种子即可找到
  19. 基于TMS32F28035的CLA学习
  20. 介绍几个ipad的使用技巧

热门文章

  1. python语言中、用来安装第三方库的命令_python安装第三方库的方法
  2. Latex固定表格图片位置
  3. Linux命令学习之一
  4. 偏光显微镜基本原理及主要用途
  5. hive 以beeline的模式启动
  6. 9.14 PreScan自动驾驶建模与仿真技术培训(第三期)
  7. 记录一下nginx代理引起的ip失真问题
  8. 为什么我们要坚持写博客?
  9. Fire (poj 2152 树形dp)
  10. Spring Cloud 异常“ Caused by: java.net.UnknownHostException: discovery.host ”