一、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性能高的原因是什么

posted on 2018-04-03 15:36  LyndonYoung  阅读(288)  评论(0编辑  收藏  举报