signed

QiShunwang

“诚信为本、客户至上”

2022秋招面试汇总

2021/6/3 17:56:35   来源:

百度暑期实习

一面

  1. C++构造函数(拷贝构造函数,赋值的时候发生了什么,为什么要用引用)
    当定义一个对象时,会按顺序做2件事情:
    分配好内存(非静态数据成员是未初始化的)
    调用构造函数(构造函数的本意就是初始化非静态数据成员)
      显然上面代码中,CLS obj;这里已经为obj分配了内存,然后调用默认构造函数,但是默认构造函数还未执行完,却调用了另一个构造函数,这样相当于产生了一个匿名的临时CLS对象,它调用CLS(int)构造函数,将这个匿名临时对象自己的数据成员m_i初始化为0;但是obj的数据成员并没有得到初始化。于是obj的m_i是未初始化的,因此其值也是不确定的
      用值传递时,会多次调用拷贝构造函数,以及析构函数,非常影响性能
    如果一个函数是pass-by-value,那么传入函数内部时,编译器会调用copy构造函数构造一份实参的副本,执行函数内部的逻辑,然后将这个副本返回,所以我们只是传值的话,是不会对原实参作改动的。
      如果设计的基类中有virtual函数,那么pass-by-reference还避免了对象切割(slicing)问题,对象切割不是多态,多态是通过指针或者引用实现的,而对象切割是派生类直接向基类传递或者强制类型转换的时候,自己(基类)的部分在转换时丢失了,就像被切割了一样。
    当然,对于built-in types , STL迭代器对象 , 函数对象可以用值传递,性能也不错

  2. C++析构函数如果直接free空间,不调用析构函数,会怎么样

  3. new 和malloc的区别
    从表面上来看, new 返回指定类型的指针,并且可以自动计算所需要大小:
    而 malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针:
    在new中,先由operator new调用malloc申请了对象数据存储大小(非全局静态成员变量+虚函数表指针大小*数量)的空间,然后赋给一个空指针,然后静态转型为目标型的指针,赋值给刚开始定义对象类型指针,然后调用了类的构造函数,对内对中的对象空间初始化赋值。
    在delete中,则是先调用了对象的析构函数,然后调用operator delete来free空间。

  4. 智能指针

  5. Raii
    RAII是Resource Acquisition Is Initialization(wiki上面翻译成 “资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。RAII的做法是使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。
    其实就是把资源都放到类中,利用类的构造和析构函数去进行资源管理

  6. linux socket编程
    socket() bind() listen() connect() accept() close() read() write() 三次握手 四次挥手

  7. 数据库b+树存储

  8. redis Zset底层数据类型(跳表?
    string
    简单动态字符串(simple dynamic string,SDS)的抽象类型,并将 SDS 作为 Redis的默认字符串表示。相对于 C 语言对于字符串的定义,多出了 len 属性以及 free 属性,常数复杂度获取字符串长度,
    链表
    双端,无环,带长度计数,可以保存各种类型
    整数集合
    压缩列表
    压缩列表的原理:压缩列表并不是对数据利用某种算法进行压缩,而是将数据按照一定规则编码在一块连续的内存区域,目的是节省内存。

  9. 山峰数组找最大值(二分