序言
大家对面试中的面经八股文是怎样的看法呢,从他的名字 八股文 就可以看出来大家可能并不喜欢他,八股文一般是 死板、浮于表面、不重实际 的特点。但是,我们需要通过辩证的角度来看待一个事情,不能单方面来定性!
一个企业很能在短时间之内考察一个人对知识的熟练程度,为了高效地判断这个人的知识体系是怎样地?也许,八股文 确实是一个不错的选择方式,快速地考察候选人在知识体系各个方面地熟悉程度。
并且我认为,我们也可以将这些知识作为我们自己检阅自己知识体系很好的方式,查漏补缺嘛,完事自己的知识体系结构不是坏事。
一. C++
1. 智能指针实现原理
智能指针采用了 RAII 的思想(在创建对象时申请资源,在析构对象时是释放资源), 常用的智能指针有 unique_ptr, shared_ptr(weak_ptr 可看作为他的补充)
。
unique_ptr
:通过删除掉拷贝构造,以及普通对象的赋值运算符重载,保证同一份资源只能被一个指针所管理。shared_ptr
:通过 引用计数 的方式实现多个指针对象管理同一份资源,但只有最后一个指针被析构时才释放资源!weak_ptr
:解决了shared_ptr
循环引用的问题,他只是使用对象,但是不会影响引用计数。
2. 智能指针,里面的计数器何时会改变
当创建,拷贝,赋值时引用计数会加一。当析构,赋值,重置时会减一。
3. 智能指针和管理的对象分别在哪个区
智能指针本身可以存在于栈区或者是堆区,但是管理的对象必须存在于堆区,因为需要堆区的资源我们手动申请释放内存。存在于栈区的对象,当函数结束时会自动销毁,如果智能指针管理栈区的对象会造成 同一个资源被析构两次。
4. 面向对象的特性:多态原理
多态的核心原则是允许不同的类通过相同的接口进行交互,但具体行为会根据实际对象的类型而有所不同。
- 静态多态:发生在编译期间,通常通过函数重载或运算符重载来实现
- 动态多态:运行时多态的核心是方法的动态绑定,基类指针或引用可以调用派生类的重写方法,具体调用哪个方法由对象的实际类型决定
动态多态的关键是 ---- 虚函数和动态绑定:
在C++中,运行时多态是通过虚函数(virtual关键字)实现的。当一个基类的指针或引用指向派生类对象时,如果调用虚函数,C++运行时会根据对象的实际类型来调用派生类中的重写函数,而不是基类中的函数。这就是动态绑定。
二、操作系统
1. 线程和进程的区别、应用场景
区别如下:
- 进程是 CPU 进行资源分配的单位,线程是一个 CPU 进行调度的单位,一个进程可以包含多个线程,线程共享进程的资源
- 进程之间的是独立的,不共享资源的;线程共享在进程中的代码区,全局区,堆区,文件描述符等资源,但是栈区是独立的
- 进程调度时切换上下文和页表等信息,开销大;线程进行切换时切换少量上下文信息,页表不用切换,开销小
- 进程之间相互隔离,一个进程的异常不会影响其他进程;但是线程之间,一个线程的异常会影响其他线程
应用场景:
- 多进程:密集型计算,因为操作系统实际按照进程为单位分配时间片资源,可以快速的处理数据
- 多线程:IO 密集型场景,大多数 IO 场景会阻塞当前线程进行切换,线程的切换开销较小
2. 多线程中各种锁,读写锁,互斥锁,自旋锁
- 互斥锁:同一时刻保证只有一个线程可以访问资源,被阻塞的线程会被阻塞,直到锁被释放。
- 自旋锁:和互斥锁的区别是,当互斥锁被占用时,线程会被阻塞,下 CPU;但是自旋锁不会阻塞,会一直判断锁的状态是否可用,当临界区的代码非常短时就避免了线程调度的开销。
- 读写锁:多个线程可以同时拥有读锁,进行读操作,但是写锁只有其他线程不持有任何锁才能获得。
3. C++内存空间结构
由下到上分别是:
- 代码段:存储代码和一些只读常量
- 数据段:存储全局变量和静态变量
- 堆区:用于动态分配的,需要我们手动申请释放
- 映射区:用于存储共享内存,共享库等
- 栈区:用于存储局部变量,栈区内存的申请释放操作系统负责
4. 内存泄露问题
当我们向堆区申请了资源却没有释放时就会导致内存泄漏,内存泄漏会导致资源无法正常。我们可以使用智能指针来管理动态分配的资源,避免内存泄漏问题。或者是使用工具 Valgrind 来检测程序是否存在内存泄漏。
文件描述符的没有正常关闭也算是内存泄漏,会导致文件描述符表被占满,无法打开新的文件。
总结
今天就到这里吧,天天复习一点,天天进步!