发布于 

c++面试知识点总结

总结回答问题重点

一、C++语法

  • 关键字:

    • const:普通变量(初始化),修饰指针(常量指针:内容不变与指针常量:地址不变),修饰函数中的参数与返回值,修饰类中的成员变量(构造函数列表初始化)与成员函数(不能修改成员变量)
    • static:初始化和作用域。静态局部变量、静态全局变量、静态函数、类成员变量、类成员函数(没有this指针)
    • volatile:取内存而不是寄存器
    • mutable:const反义词
    • explicit
    • inline:编译器编译时将其内联展开。不压栈,省去栈空间的消耗。
    • extern:c连用。只声明不定义。
  • main函数执行之前和之后执行的代码是什么:栈,bss,data,argc,argv

  • 结构体内存对齐:三原则,alignof,alignas,#prama pack(push,1),__attribute__(packed)

  • 指针与引用的区别:地址,别名,改变,内存,NULL

  • 堆和栈的区别:申请方式,大小限制,增长方向,碎片,速度,内存管理方式

  • new/delete与malloc/free的异同:运算符/库函数,自动分配/手工计算,类型安全,调用析构和构造函数,返回值类型,异常抛出,支持重载

  • 宏和typedef:变量/类型别名,预编译/编译,是够检查数据类型,是否是语句

  • struct与class:公有/私有,private继承/public继承

  • define与const:编译阶段,安全性,内存占用

  • 内存五大分区、内存的分配方式:栈区,堆区、全局变量与静态变量(bss,data),常量区,代码区

  • 静态内存分配与动态内存分配:编译/运行,堆是动态,栈有静态和动态,动态有编译器控制

  • 深拷贝与浅拷贝:指针/内容

  • 枚举(enum) 和 宏(#define),typedef,using 的区别:阶段/是否占用内存

  • struct 和 union 的区别:是否共享一个空间

  • 右值引用是什么 移动语义是什么 move函数的作用: 不可取到地址,主要用于实现移动语义。将右值的内存资源移动为自己使用,减小了多次申请释放内存空间的开销。move函数将左值转化为右值。

  • move和forward区别:move强制转化为右值,forward绑定到右值转为右值,绑定到左值,转化后仍为左值。

  • RVO返回值优化是什么:省略掉两次通过拷贝构造函数创建临时对象的过程,大大节省了开销。

  • 简述智能指针:unique_ptr,shared_ptr,weak_ptr.引用计数是线程安全,智能指针托管的对象需要加锁。

  • C++有哪四种强制类型转换:static_cast,const_cast,reinterpret_cast,dynamic_cast.(基类指针转换为派生类指针)

  • 简述STL库:容器,算法,迭代器,配置器,适配器,仿函数。

  • 简述STL库中的容器以及特点:vector:底层由数组实现。list:双向链表。deque:中央控制器和多个缓冲区。map、set:红黑树。unordered:hash表,无序不可重复。stack:list或是deque,先进后出。queue:先进先出。priority_queue默认大顶堆。

  • 简述vector的存储机制:三个指针,start、finish、end_of_storage.动态扩容:申请一个更大的空间,将原空间的数据拷贝至新的空间,释放掉原空间。动态扩容机制代价较高。

  • 简述list的存储机制:闭环双向链表。有一个指向尾部节点的空白头节点,只需要空白头节点便可遍历整个链表,prev和next。

  • 简述deque的存储机制:中央处理器主控,一小块的连续存储空间,每个元素都是一个指针,指向一个较大的连续存储空间。叫做缓冲区。cur。first。last。node:指向中控器。

  • 什么情况下选择unorder_map 和 map :查询次数、查询时间。

  • 简述迭代器失效的情况:数组型:没有重新分配空间,会导致该元素及之后的迭代器都失效。链表型:只会让该位置的失效。红黑树:让该位置的迭代器失效。

  • 没有迭代器的容器有哪些 queue。stack。priority_queue.

  • 简述public,protected,private访问修饰符的区别:修饰成员,可访问性。交集取最小,public>protected>private.

  • 派生类不能继承基类的哪些东西:构造函数,析构函数。友元函数。赋值运算符继承会会将基类的进行隐藏。

  • 友元是什么:友元函数和友元类,声明后即可访问该类所有的public,protected,private。

  • this指针是什么:成员函数的隐形形参,将该对象的地址赋给this指针。const,友元、static无指针。

  • 简述C++中的多重继承 (菱形继承):域限定符,虚继承class A;class B1:public virtual A;class B2:public virtual A;class D:public B1,public B

  • 什么情况下需要使用初始化列表初始化成员变量:const,引用,类中有需要参数初始化的对象。派生类初始化基类对象。

  • 类成员变量初始化的顺序:按照类中的声明顺序进行初始化,并不是按照初始化列表的顺序进行初始化。

  • 简述C++中的多态机制 (虚函数,多态相关问题):一个接口的多种形态,条件:虚函数重写,指针或引用调用。虚函数表:有虚函数的类在编译时期都会生成一个 虚函数表,虚函数表实质上是一个 指针数组,存放 指向虚函数的指针,通过该指针我们可以调用虚函数;另外虚函数表是类对象之间共享的,在各个类对象之间不会存储整个虚函数表,只存放一个指向该 虚函数表的指针,该指针通常是放在类内存的最前面。这就是虚函数表。该虚函数表存放在全局静态数据区的DATA段。

  • 在生成派生类过程中,对虚函数表的操作有三个步骤:
    将基类中的虚函数表指针拷贝到派生类中;
    派生类对基类虚函数进行覆盖(重写);
    派生类将自己新增的虚函数依次添加在虚函数表后。

延伸1:虚函数表中的虚函数指针是如何实现偏移的?
通常编译器会将虚函数表指针放在对象内存的最前面,我们可以通过取该对象的地址得到该虚函数表指针,进而得到虚函数表,也就是一个指针数组(指针属于函数指针,指向虚函数),遍历这个数组,就可以得到我们想要的虚函数。

延伸2:每个实例化对象的虚函数表是否相同?
相同,因为虚函数表属于类对象之间共享的,只会有一个,每一个实例化对象都只会存放一个虚函数表指针,指向共享的虚函数表。

  • 虚函数与纯虚函数的区别 :只声明不定义,必须在派生类重写虚函数;抽象类不能实例化,只能被继承。
  • C++中哪些函数不能是虚函数:构造(派生类无法创建,无法调用基类构造函数),inline(编译期),友元(不属于类成员),静态(类共享)。
  • 静态联编与动态联编 (静态绑定与动态绑定):编译,运行。重载,多态。
  • 重载,隐藏,覆盖的区别:函数名相同,参数类型(个数)不同(同一个类)。隐藏:函数名相同,参数不同;都相同没有virtual。覆盖:多态。
  • 构造函数与析构函数能否为虚函数 :构造(x,无法调用基类的构造函数)析构(对,只能基类,无法调用派生类的析构函数)
  • 析构函数可以抛出异常吗 :内存泄漏,析构函数用于处理异常。
  • 空类中自带哪些函数 :构造、析构、拷贝构造、赋值、取址、取址const
  • 抽象类和接口的区别 :抽象类:纯虚函数,不能实例化;接口:类中没有任何成员变量,成员函数公有并且都是纯虚函数。

    二、MySQL数据库

  • Mysql的事务 事务的四大特性 事务带来的问题
  • MVCC
  • Mysql的InnoDB和MyISAM有什么区别
  • 执行一条查询语句的流程
  • redolog和binlog
  • 线上要给热点数据表添加字段该怎么操作
  • Msyql的索引的底层实现吗?为什么不用有序数组、hash或者二叉树实现索引
  • 怎么查看索引是否生效?什么情况下索引会失效呢?
  • 有哪些种类的索引
  • SQL优化
  • 聚簇索引和非聚簇索引
  • 回表
  • 最左前缀原则
  • 索引下推
  • 主键使用自增ID还是UUID
  • 控制并发的访问资源
  • 死锁
  • 主从复制
  • 分库分表

    三、redis

  • 什么是Redis 远程字典服务,基于内存、可持久化的日志型k-v数据库。缓存,分布式锁。
  • 基本数据结构类型:String(SDS,len标记buf的长度,free标记buf中未使用元素的个数,o(1)获取字符串长度,buf[]存放元素的坑),Hash(缓存用户信息(ziplist,hashtable)),List(ziplist,linkedlist),Set(用来保存多个的字符串元素,intset,hashtable),zset(ziplist,skiplist)
  • 特殊数据结构:Geospatial(地理位置),Hyperloglog(基数统计算法),Bitmap(用一个比特位映射某个元素的状态)
  • 为什么快 基于内存存储、高效的数据结构(动态字符串(字符串长度处理、空间预分配、惰性空间释放、二进制安全),双端链表,压缩链表、字典、跳表(增加多级索引))、合理的数据编码、合理的线程模型(epoll单线程)、虚拟内存(暂时把不经常访问的数据从内存交换到磁盘)
  • 缓存击穿、缓存穿透、缓存雪崩(热点key在某个时间点过期的时候,大量的请求打到db;不存在;大批量数据过期,查询数据量巨大)
  • 热key问题解决:增加分片副本,均衡读流量;将热key分散到不同的服务器中;二级缓存,减少redis的读请求。
  • redis过期策略和内存淘汰策略:
    • 惰性过期,定期过期。redis采取的是定期过期,每隔100ms就随机抽取一定数量的key来检查和删除的。但是呢,最后可能会有很多已经过期的key没被删除。这时候,redis采用惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且已经过期了,此时就会删除。
    • lru和lfu。
  • 用途:缓存,排行榜,计数器,共享Session,分布式锁(setnx),社交网络,消息队列(业务解耦、流量削峰),位操作。
  • 持久化:RDB(内存数据以快照形式保存在磁盘,save,bgsave,save m n,适合大规模的数据恢复场景,备份和全量复制)和AOF(采用日志的形式来记录一个写操作,追加到文件中,重启时再重新执行AOF文件)(优点:数据的一致性和完整性更高 缺点:AOF记录的内容越大,文件越大,数据恢复变慢)
  • redis的高可用:主从模式、哨兵模式、集群模式。
    • 全量复制:一般当slave第一次启动连接master,就采用全量复制
    • 增量复制:如果再次发生更新,就会触发增量复制
    • 哨兵模式:由一个或多个哨兵实例组成的哨兵系统,它可以监视所有的Redis主节点和从节点,并在被监视的主节点进入下线状态时,自动将下线主服务器属下的某个从节点升级为新的主节点
    • 集群模式:cluster集群,redis的分布式存储。各个节点之间通过gossip协议进行通信。ping、pong、meet、fail。哈希槽插槽算法,每个key都会对应一个编号在 0~16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
  • redis分布式锁:控制分布式系统不同进程共同访问共享资源的一种锁的实现。
    • 命令setnx + expire分开写
    • setnx + value值是过期时间
    • set的扩展命令(set ex px nx)
    • set ex px nx + 校验唯一随机值,再删除
  • redisson,解决锁过期释放,业务没执行完的问题。只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了锁过期释放,业务没执行完问题。
  • redlock算法 解决一个master的发生故障的问题。搞多个Redis master部署,以保证它们不会同时宕掉。并且这些master节点是完全相互独立的,相互之间不存在数据同步。同时,需要确保在这多个master实例上,是与在Redis单实例,使用相同方法来获取和释放锁。
  • 跳表:
    • 跳跃表是有序集合zset的底层实现之一。
    • 跳跃表支持平均O(logN),最坏 O(N)复杂度的节点查找,还可以通过顺序性操作批量处理节点。
    • 跳跃表实现由zskiplist和zskiplistNode两个结构组成,其中zskiplist用于保存跳跃表信息(如表头节点、表尾节点、长度),而zskiplistNode则用于表示跳跃表节点。
    • 跳跃表就是在链表的基础上,增加多级索引提升查找效率。
  • 缓存和redis保证双写一致性:1.如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。2.如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题。
    • 缓存延时双删
    • 删除缓存重试机制
    • 读取binlog异步删除缓存
  • 为什么Redis 6.0 之后改多线程呢 redis还是使用单线程模型来处理客户端的请求,只是使用多线程来处理数据的读写和协议解析,执行命令还是使用单线程。这样做的目的是因为redis的性能瓶颈在于网络IO而非CPU,使用多线程能提升IO读写的效率,从而整体提高redis的性能
  • 事务:Redis通过MULTI、EXEC、WATCH等一组命令集合,来实现事务机制。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。简言之,Redis事务就是顺序性、一次性、排他性的执行一个队列中的一系列命令。
  • Redis的Hash 冲突怎么办
    Redis 会对哈希表做rehash操作,也就是增加哈希桶,减少冲突。为了rehash更高效,Redis还默认使用了两个全局哈希表,一个用于当前使用,称为主哈希表,一个用于扩容,称为备用哈希表。
  • Redis提供两个指令生成RDB,分别是save和bgsave。
    • 如果是save指令,会阻塞,因为是主线程执行的。
    • 如果是bgsave指令,是fork一个子进程来写入RDB文件的,快照持久化完全交给子进程来处理,父进程则可以继续处理客户端的请求。
  • Redis底层,使用的什么协议 RESP Redis Serialization Protocol
  • 布隆过滤器 利用k个哈希散列函数,将A中的每个元素映射到一个长度为a位的数组B中的不同位置上,这些位置上的二进制数均设置为1。如果待检查的元素,经过这k个哈希散列函数的映射后,发现其k个位置上的二进制数全部为1,这个元素很可能属于集合A,反之,一定不属于集合A。
    布隆过滤器并没有存放完整的数据,它只是运用一系列哈希映射函数计算出位置,然后填充二进制向量。如果数量很大的话,布隆过滤器通过极少的错误率,换取了存储空间的极大节省。

    四、操作系统

  • 虚拟内存:MMU(内存管理单元)、TLB(快表缓存)、多级页表(减少内存的占用)、内存分配(伙伴算法、slab算法)
  • 线程进程的基本概念和区别:调度/分配资源, 1个/多个,数据同步与共享,CPU与内存消耗,创建销毁切换时间,可靠性
  • 进程间通信:基本概念和原理,通信效率,是否涉及系统调用
  • 死锁条件,检测恢复预防
  • 同步:原子操作,CAS(比较并交换)/FAA(fetch&add),互斥锁,条件变量,RCU(READCOPY UPDATE)
  • 底层IO模型
  • 多线程多进程
  • 协程vs线程
  • inode,软/硬连接,文件描述符
  • 零拷贝

五、计算机网络

参考链接:计网相关

  • OSI七层模型:应用、表示、会话、传输、网络、数据链路、物理

  • 有连接(需要连接并维持)、无连接、可靠、不可靠、有状态(记忆)、无状态

  • HTTP:请求报文(行、头、空行、体)、响应报文(状态行 + 响应头 + 空行 + 响应体)

  • 状态码:1xx:信息,要求请求者继续操作;2xx,成功,OK表示客户端请求成功,200OK,客户端请求成功;3xx,重定向,需要进一步的操作以完成请求,301永久转移到其他URL,302网页临时跳转;4xx,客户端错误,请求包含语法错误或无法完成请求,400有语法错误,不能被服务器理解,401请求未经授权,404请求资源不存在;5xx,服务器错误,500服务器内部发生了不可预期的错误,503服务器不能处理客户端的请求。

  • get和post的区别:获取/发送,参数可见/不可见,安全/不安全,大小限制/无限制

  • 输入URL发生了什么:DNS(域名转换IP地址);浏览器连接到服务器HTTP/80端口,三次握手TCP连接;浏览器发送HTTP请求,读取URL域名后的文件发送给web服务器;服务器接收请求并返回HTTP响应,响应体中存放HTML文本;挥手释放TCP连接,keep-alive保持一段时间后再释放;浏览器解析html文本并显示。

  • 长短连接的区别:CONNECTION字段:keep-alive/closed,HTTP1.0默认短连接,1.1默认长连接。

  • cookie和session:session存储在服务器中,数据可以保存在内存或数据库中;cookie存储在客户端浏览器中,会记录下该浏览器对应的sessionid,每次HTTP请求都会把sessionid发过来,这样服务器就能识别该用户了。

  • cookie被禁用:可以将URL重写,将sessionID直接附加在URL路径的后面。

  • HTTP和HTTPS

    • 对称加密算法:加密和解密采用同一个密钥。 这种加密方式由于需要传输密钥,所以有很大的安全性问题。常见的对称加密算法有DES,AES。

    • 非对称加密算法:加密和解密使用的并不是同一个密钥。 通常有两个密钥,分别称为公钥私钥,公钥可以对外公布,私钥只能持有人自己所拥有不能对外公开。非对称加密算法有效的避免了密钥的传输安全性问题。常见的非对称加密算法有RSA

    • 数字签名算法:非对称加密。

      • 数字签名
        对于明文信息先进行哈希算法求得信息摘要,后再用自身私钥进行加密后求得数字签名。数字签名的作用是证明该信息是否为本人所写。

      • 数字证书
        将自身的公钥和一些相关信息,交给CA(certificate authority 认证机构)并利用CA的私钥进行加密后得到数字证书。数字证书的作用是传递公钥。

    • HTTP优势:安全性,完整性,身份认证性,不可否认性

      HTTP Over SSL:SSL协议对浏览器与web服务器之间的通信进行了加密

      1. 用户向Web服务器发起访问请求;
      2. Web服务器将自己的CA认证的数字证书发给用户;
      3. 用户拿到数字证书,并用自己浏览器内置的CA证书解密得到Web服务器的公钥;
      4. 用户使用服务器的公钥对于对称加密算法的密钥进行加密,发送给Web服务器;
      5. 服务器收到后,用自己的私钥解密,得到对称加密算法的密钥;
      6. 双方使用对称加密算法开始通信。
    • 总结:通过CA体系发送公钥(或者说是数字证书);通过非对称加密算法确定对称加密的密钥;通过对称加密算法进行网络通信

  • TCP协议:面向连接,可靠、基于字节流(发送接收没有边界限制)的全双工端对端通信协议

  • TCP头:源端口(16)、目的端口(16)、序列号(32)、确认号(32)、头部长度(4bit):最小为20字节(0101),最大为60字节(1111) 保留(6bit) 标志位(6bit) 窗口大小(16bit)校验和(16)紧急指针(16)

  • 三握四挥

  • 两次可以吗?不,一是防止失效的SYN报文到达服务器,二是第二次的报文丢失服务器已经进入established状态。

  • 挥手需四次?防止服务端有未完成传输的数据。

  • 客户端2MSL?1.保证客户端最后发送的ACK到达客户端,2.防止旧连接中的报文影响新连接,所有报文在网络中已经消息

  • 半连接/全连接:半连接SYN-REVD状态,全连接三次握手的连接。

  • SYN泛洪攻击:黑客伪造不存在的IP地址,向server端发送SYN请求,导致半连接状态队列满。

    • 过滤网关防护 :如设置SYN代理,让代理为服务器处理SYN请求,如果收到了客户端的ACK包那么就向服务器完成三次握手。
    • 增大半连接队列容量
    • 缩短超时时间与减少重传次数
    • SYNcookies技术
  • 客户端故障:服务端会有一个Keep-Alive心跳包机制,也就是定期内会通过发送数据包检测客户端是否正常运行,那么就认为客户端已经出现故障, 服务器自动断开。

  • TCP可靠传输

    • 连接管理:三握四挥
    • 序列号+确认号
    • 校验和
    • 超时重传机制
    • ARQ(停等ARQ,回退n帧ARQ,选择重传ARQ)
    • 滑动窗口流量控制:当接收缓冲区的剩余空间过小不能接收发送方的数据时,会提示发送方降低发送速率,从而防止丢包。
    • 拥塞控制:满开始,拥塞避免,快重传(3ACK),快恢复(3重复确认)
  • UDP(USER DATAGRAM PROTOCOL):无连接,不可靠,基于数据报。源端口号(16bit) + 目的端口号(16bit)UDP总长度(16bit):此处的总长度为UDP 头部+数据部分 的长度,数据部分的长度受数据链路层MTU的限制,通常最大为1472字节(1500-20字节IP头部-8字节UDP头部)。UDP检验和(16bit):当检验到错误时,UDP不做纠正,而是直接将数据丢弃。

  • TCP/UDP区别

    • TCP是有连接,可靠的,基于字节流的协议;UDP是无连接,不可靠,基于数据报的协议
    • TCP头部结构复杂,网络开销和时延都较大;UDP头部结构较为简单,网络开销和时延都较小。
    • TCP能通过建立连接,确认序号,滑动窗口,超时重传,拥塞控制,检验和等方式让数据包安全准确的传到对端;UDP则是提供不可靠的交付。
    • TCP一般用于文件传输,收发邮件,远程登录,HTTP等,UDP一般用于即时通信,比如语音,视频,直播,DNS等。
  • IP协议:无连接,不可靠,点对点。IP数据报头部最小为20个字节,最大为60个字节。

  • NAT协议的作用实现公网IP地址与私网IP地址之间的相互映射转换,使得一个公网IP地址下能够有多个私网IP。

    • 解决了IPv4地址枯竭的问题;
    • 主机的安全性得到了保障,因为就算暴露了私网IP也没有关系。
  • ARP

    从IP地址到MAC地址的映射。

    主机发送信息时将包含目标IP地址的ARP请求在局域网进行广播,并根据返回的消息确定目标IP地址的 MAC地址,以 <IP,MAC> 形式存入 ARP缓存表。


本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站由 @ATing 创建,使用 Stellar 作为主题。