C++后端面试知识精选系列(二)

1.new和malloc的区别?

参考解答:1)new和malloc都是开辟内存空间用的,且都是在堆区开辟,但是malloc只负责开辟空间,不能初始化,需要用户初始化,new不但能开辟空间还能初始化。2)malloc是函数,开辟内存需要传入开辟空间大小,返回类型是void*,需要转换成指定类型的地址,new是运算符,开辟内存需要指定类型,返回指定类型的地址,因此不需要转换。3)malloc开辟内存失败返回NULL,new开辟内存失败抛出bad_alloc类型的异常(new底层实现也是调用的malloc函数)。4)nalloc开辟空间用free释放,new开辟的用delete释放,删除数组时要加[]。5)new/delete会调用对象的构造函数/析构函数以完成对象的构造/析构,而malloc不会。6)new/delete可以被重载,而malloc/free不允许被重载。

2.进程和线程的区别?

参考解答:1+进程是操作系统进行资源分配和调度的基本单位,而线程是操作系统进行运行调度的最小单位,包含在进程中,是进程中实际工作的单位;2)线程存在于进程之中,与进程是多对一的关系,一个进程可以存在多个线程,这些线程共享进程资源;3)进程有自己的独立地址空间,每启动一个进程,系统就会为他分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。线程共享进程空间及数据。4)线程之间的通信更方便(共享全局变量、静态变量等数据),而进程通信需要以通信方式(管道、消息队列、信号量、共享存储、socket、streams)进行。4)多进程程序更健壮,多线程程序只有有一个线程死掉,整个进程也死掉了。而一个进程死掉,不影响另外一个进程,因为进程有独立空间。

3 介绍下线程池?

参考解答:由于线程的创建和销毁需要消耗资源,当线程频繁创建和销毁时或者线程创建和销毁的时间大于线程执行的时间,那么单纯的采用线程创建/销毁策略明显不合适,所以有了线程池的概念,线程池中存放一定数量创建好的线程,需要用的时候拿出来用,用完之后再放到池子里。线程池的好处就是:1)降低了频繁创建销毁线程的开销;2)提高了响应速度;3)提高了线程的可管理型;

线程组成部分有:线程池管理器(创建并管理线程池)、工作线程(线程池中的线程)、任务队列(存放未处理的任务)、任务接口(每个任务必须实现的接口,以供线程调度任务的执行)。线程池工作流程如下:

 4. 介绍下epoll?

参考解答:epoll是在linux2.6内核中提出的,是之前select和poll的增强版本。相对于select和polll来说,epoll更加灵活没有描述限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样用户空间和内核空间之间的数据只拷贝一次。epoll使用需要使用三个接口:

#include <sys/epoll.h>
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

int epoll_create(int size)创建一个epoll的句柄,size告诉内核要监听的数目。使用完eplll后,必须调用close()关闭。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event),epoll的事件注册函数,它不同select()在监听事件时告诉内核要监听什么类型的事件,而是先注册要监听的事件类型。epfd是epoll_create()的返回值,第二个参数表示动作,用三个宏来表示:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd;

第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:

struct epoll_event {
  __uint32_t events;  /* Epoll events */
  epoll_data_t data;  /* User data variable */
};

events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout):等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

5. 介绍下TCP的三握四挥?

参考解答:见TCP三次握手,四次挥手详解

6. 一个空类会生成那些成员?

参考解答:默认构造函数、默认析构函数、默认拷贝构造函数、默认拷贝赋值函数

7.struct和class有哪些区别?

参考解答:最大的区别是class默认继承访问权限是private,而struct是公public继承。class默认访问属性是私有,而struct默认是公有。并且class具有继承、多态等性质,struct不具备。class能定义函数模板,struct不行。

8. 必须在构造函数初始化式里进行初始化的数据成员有哪些?

参考解答:常量成员、引用类型、对象成员

9. 介绍下虚函数?

参考解答:虚函数是 C++实现多态的重要保证,当类中有虚函数时,就有存在一个虚函数指针(vfptr)指向虚函数表(vftable),虚函数表存放着虚函数的地址,子类继承时虚函数表和指针都继承了,当子类重写父类的虚函数之后,子类的虚函数表内存的地址就变成子类的重写的虚函数的地址了。当父类指针或者引用指向子类时,就产生了多态。纯虚函数,就是在参数列表后直接=0,此时这个类被称为抽象类,不能实例化对象,子类必须重写父类的纯虚函数,否则子类也是抽象类。

10. 说一下static的用法?

参考解答:修饰全局变脸、全局函数、局部变量、类的成员函数、类的成员变量。详见C++后端面试知识精选系列(一)

11. 讲一下快速排序?

参考解答:核心思想:让每个元素回归到应该处于的位置,详见快速排序详解

12. 说说C++怎么防止头文件重复包含?

参考解答:C++中提供两种方式防止头文件重复包含:

(1)ifndef语句:其作用是两个文件不会重复包含。

#ifndef _name_
#define _name_

//头文件主体


#endif

优点:1)不受编译器的限制;2)不仅仅局限于避免同一个文件被重复包含,也能避免内容完全相同的两个文件(或代码片段)被重复包含。

缺点:1)如果不同头文件中 _name_恰好相同,可能就会导致明明你看到头文件存在,却提示找不到声明的情况;

           2)编译器每次都需要打开头文件才能判断是否有重复定义,因此打编译大型项目的文件时编译速度较慢。

(2)#pragma once语句。作用:物理上同一个文件不会被重重复包含

#pragma once

//头文件主体

优点:1)避免#ifndef因为_name_重名的问题。

           2)由于编译器不需要打开头文件就能判定是否有重复定义,因此在编译大型项目时,比#ifndef更快。

缺点:1)#pragma once只针对同一文件有效,对相同的两个文件使用无效。

           2)#pragma once兼容性可能不够好

有时可以两者混合使用,只要使用#ifndef....依旧避免不了宏重名的问题,并且不支持#pragma once的编译器依然报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值