一、C++基础问题
1.new/malloc的区别
new是运算符,malloc()是一个库函数;
new会调用构造函数,malloc不会;
new返回指定类型指针,malloc返回void*指针;
new会自动计算需分配的空间,malloc不行;
new可以被重载,malloc不能。
2.指针和引用的区别
指针是一个实体,而引用仅是个别名;
引用使用时无需解引用(*),指针需要解引用;
引用只能在定义时被初始化一次,之后不可变,而指针可变;
引用没有const,指针有const;
引用不能为空,指针可以为空;
从内存分配上看,指针变量需分配内存,引用则不需要;
sizeof(引用)得到所指对象的大小,sizeof(指针)得到指针本身的大小;
指针和引用的自增(++)运算意义不一样。
3.为什么析构函数要设置成虚函数?
在多态中,当使用基类指针或引用操作派生类对象时,如果不把析构函数定义为 virtual 函数,
则 delete 销毁对象时,只会调用基类的析构函数,不会调用实际派生类对象的析构函数,这样可能造成内存泄露。
class A {};
class B : public A {};
A a = new B();
4.static_cast,reinterpret_cast,dynamic_cast, const_cast的用法
static_cast:没有在运行时检查来保证转换的安全性。
主要用于层次结构间的基类和子类的指针或引用的转换,向上转换是安全的(子类转换成基类),向下转换不安全。
把空指针转换成目标类型的指针。
dynamic_cast::dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。但其具有类型检查功能,比static_cast更安全。
reinterpret_cast:功能较多。
const_cast :修改类型的const属性。
5.sizeof和strlen
sizeof是返回的是该对象的实际占用的空间大小,strlen返回字符串的长度,遇到\0结束。
int arr[10]
char*str = “abdsa”
char ss[] = "0123456789"
sizeof(ss) = 11 //算上\0
strlen(ss)=10
sizeof(arr)=40
sizeof(str)=4 // 指针的大小
strlen(str)=5
6.C++的多态是怎么实现的
多态的实现有静态和动态两种方式,静态主要通过模板和重载来实现,在编译期间实现,动态主要通过虚函数实现,在函数前加virtual关键字。
存在虚函数的类都有一个一维的虚函数表叫做虚表,虚标在类里面,而每个对象都存在一个指向虚表的指针,称为虚指针,虚表和类对应,虚指针和对象对应。
7. extern C的作用
由于C和C++编译出来的函数命名不同,使用extern关键字是为了告诉编译器,使用C编译器编译。
8.Makefile里面$@,$^,$<代表的意义分别是什么
$@:目标文件,$^:所有的依赖文件,$<:第一个依赖文件。
9.进程间通信方式以及什么情况下用哪种合适?
文件、 信号、管道、共享内存、消息队列、socket
10.什么情况只能用初始化列表初始化
const变量、类成员中的引用
static只能通过类外重定义初始化
static const只能通过类中直接用=进行赋值。
11.深拷贝和浅拷贝
默认的拷贝是浅拷贝,浅拷贝不申请内存,意思就是说若一个类中有一个指针,若执行A=B,A,B两个对象的指针是指向同一块内存的,深拷贝则会重新申请内存。
12.什么情况下调用拷贝构造,什么情况下调用operater =
A a = new A();
A b = a;(拷贝构造)
A c;
c = a;(=操作符)
13.const修饰函数
若const放在函数后,则表示该函数不能修改对象中的成员,若const放在前面,则表示该函数的返回值不能被修改。
14.sizeof结构体大小
结果为最大类型的整数倍
每个成员的首偏移为该类型的整数倍。
例如:
struct Test {
char c; // c首偏移为0,是1整数倍
int a; // a的首偏移为1,不是4的倍数,则c补全3个字节,
double b // b的首偏移为8,是8的整数倍。
};
15.sizeof类的大小
l 类中的成员也存在和struct相同的对齐方式
l 空类的大小为1
l 多个虚函数只有一个虚表指针
l 每个虚继承都存在一个指向父类的指针
l 静态成员不占用类空间
l 没有继承的时候或存在虚继承的时候,有虚函数就存在虚指针,若是普通继承,虚函数会加到父类的虚表中,即不存在虚指针。
16.抽象基类和纯虚函数的意义
l 为了方便使用多态。
l 有可能基类并不适合生成对象。
17.虚继承的意义
虚继承是为了解决多继承的父类成员的重复问题,即菱形继承问题。
18.重载和重写的区别
重载是允许存在多个同名函数(编译期多态)
重写是子类重写父类的虚函数(运行期多态)
19.explicit的作用
禁止构造函数自动进行隐式类型转换
例如CBook中只有一个成员price,构造对象时避免出现 CBook book = 9.8这种。
二、网络相关
1.画TCP/IP的三次握手、四次挥手状态图,并指明哪个阶段是time_wait以及time_wait的原理。
2.socket编程,boost.asio网络编程库
3.用过哪些RPC框架,thrift是线程安全的嘛以及实现原理
三、问题定位
gdb常用命令,如何做性能分析、怎么才可以生成core文件、内存泄露怎么定位
perf和strace两个命令的用法。
四、多线程问题
项目中哪些模块是多线程的,遇到过哪些问题,怎么解决的
同步、异步怎么实现
五、设计模式
用过哪些设计模式,实现个单例模式
class Test { private: Test() {} Test(const Test& test) {} Test& operator(const Test& test) {} static Test& m_instance; public: static Test* getInstance() { // 考虑线程安全加锁 if (m_instance == null) { m_instance = new SingletonDemo1(); } return m_instance; } };
怎么不用锁实现单例模式?
六、stl/boost库
1.stl常见容器是怎么实现的
2.hash_map和map的区别
hash_map构造需要hash函数,map需要比较函数,hash_map用hash表存储,map使用红黑树,map是自动排序的,hash_map的查找速度快。
3.vector的内存问题
自动内存增长,内存不足时,首先会申请更多的内存,之后将现有函数拷贝,最后删除掉旧的内存,此过程很耗时。
clear()函数并不会回收内存,只是清空数据,回收内存要使用swap函数。
4.stl的空间配置器
当用户空间申请大于128的时候,使用一级配置器,否则使用二级,二级主要使用内存池,一级直接使用malloc,free并增加了set-handle机制。
5.map是怎么实现的,介绍下红黑树
6.vector会随着数据增加影响迭代器嘛
会,因为vector在内存不足时会清空之前的内存。
7.智能指针是怎么实现的
一般来说,智能指针的实现需要以下步骤:
(1)一个模板指针T* ptr,指向实际的对象。
(2)一个引用次数(必须new出来的,不然会多个shared_ptr里面会有不同的引用次数而导致多次delete)。
(3)重载operator*和operator->,使得能像指针一样使用shared_ptr。
(4)重载copy constructor,使其引用次数加一。
(5)重载operator=,如果原来的shared_ptr已经有对象,则让其引用次数减一并判断引用是否为零(是否调用delete)。然后将新的对象引用次数加一。
(6)重载析构函数,使引用次数减一并判断引用是否为零(是否调用delete)。
七、算法、数据结构、代码题(算法会要求说时间复杂度)
1.实现一个string(可以考到C++许多基础的东西)
2.插入排序
3.冒泡排序
4.字符串压缩(去掉重复的字符并记录出现个数)
5.堆排序
6.topK问题(限制内存/不限制内存)
7.实现单例
8.查找数组的第N个值
9.查找链表的第K个节点
10.判断链表是否有环
11.遍历二叉树(一般写出递归方法,要求转非递归),递归转非递归用栈
12.链表的倒置
13.快排的递归和非递归实现
14.合并两个有序数组(链表)
15.找出最长的递增子序列
16.按层遍历二叉树(找出二叉树节点个数)
17.两个超级大的数相乘(超过long的表示范围)
18.如何实现一个LRU
使用一个双向链表加一个hash表
插入:当cache未满时,新的数据只需要插到链表头部即可,时间复杂度为O(1)。
替换:当cache满了时,将新的数据插入到链表头部,并删除链表的尾部节点。时间复杂度为O(1)。
查找:当数据查询到时,将此数据移动到链表头部。
八、脚本语言
1.awk的常见用法
九、其它
1.CAP理论
关于CAP理论,C表示一致性,A表示可用性,P表示容忍网络分区,
- 数据一致性(consistency):如果系统对一个写操作返回成功,那么之后的读请求都必须读到这个新数据;如果返回失败,那么所有读操作都不能读到这个数据,对调用者而言数据具有强一致性(strong consistency) (又叫原子性 atomic、线性一致性 linearizable consistency)
- 服务可用性(availability):所有读写请求在一定时间内得到响应,可终止、不会一直等待
- 分区容错性(partition-tolerance):在网络分区的情况下,被分隔的节点仍能正常对外服务。一个分布式系统里面,节点组成的网络本来应该是连通的。然而可能因为一些故障,使得有些节点之间不连通了,整个网络就分成了几块区域。数据就散布在了这些不连通的区域中。这就叫分区。
在某时刻如果满足AP,分隔的节点同时对外服务但不能相互通信,将导致状态不一致,即不能满足C;如果满足CP,网络分区的情况下为达成C,请求只能一直等待,即不满足A;如果要满足CA,在一定时间内要达到节点状态一致,要求不能出现网络分区,则不能满足P。
因为分布式系统中,网络分区是一个无法避免的事实,所以P是基础,分布式系统大都通过复制来提高可用性,因为只要存在复制就没法保证强一致性。
2.介绍下一致性hash算法
3.zookeeper的分布式锁是怎么实现的
4.数据库的事务问题,sql在计划层次可以做哪些优化,llvm性能高的原因是什么