从今天起,豆芽有空也尽己所能,帮助一下大家。

面经来源:https://www.nowcoder.com/discuss/718024?source_id=discuss_experience_nctrack&channel=-1


1. epoll事件时具体发生了什么

从用户发起读取数据(read())开始,陷入内核。

首先创建一个epoll对象,然后使用epoll_ctl对这个对象进行操作(添加、删除、修改),把需要监控的描述符加进去,这些描述符将会以epoll_event结构体的形式组成一颗红黑树(说明查询的复杂度降为logn了),接着阻塞在epoll_wait,进入大循环,当某个fd上有事件发生时,内核将会把其对应的结构体放入一个链表中,返回有事件发生的链表,用户再遍历这个链表查看具体是哪个事件。流程如下图:

img

最后,内核空间将数据和事件数量放入(write())共享内存中。用户再从共享内存中读取数据(read())


2. dynamic_cast具体是怎么用的

static_cast用于将一种数据类型强制转换为另一种数据类型。什么都可以转,最常用。如下:

   int a = 7;  
   int b = 3;  
   double result = static_cast<double>(a) / static_cast<double>(b); 

但是在进行下行转换(把基类的指针或引用转换为派生类表示)时,由于没有动态类型检查,是不安全的。

向上转换:指子类向基类转换。

向下转换:指基类向子类转换。

这两种转换,因为子类包含父类,子类转父类是可以任意转的。但是当父类转换成子类时可能出现非法内存访问的问题。

img

dynamic_cast

正因为static_cast从基类向子类转换时不安全,所以又引入了dynamic_cast。dynamic_cast只能用于含有虚函数的类转换,用于类向上和向下转换。

dynamic_cast通过判断变量运行时类型要转换的类型是否相同来判断是否能够进行向下转换。dynamic_cast可以做类之间上下转换,转换的时候会进行类型检查,类型相等成功转换,类型不等转换失败。

运用RTTI技术,RTTI是“Runtime Type Information”的缩写,意思是运行时类型信息,它提供了运行时确定对象类型的方法。在c++层面主要体现在dynamic_cast和typeid,vs中虚函数表的-1位置存放了指向type_info的指针,对于存在虚函数的类型,dynamic_cast和typeid都会去查询type_info

   #include <stdio.h>  
   #include <stdlib.h>  
   #include <string>  
   #include <iostream>  
   using namespace std;  
   class Base{  
   public:  
       Base() {};  
       virtual ~Base() {};  
   };  
   class Inherit :public Base{  
   public:  
       Inherit() {};  
       ~Inherit() {};  
       void show();  
   };  
   void Inherit::show(){  
       std::cout << "Inherit funtion" << std::endl;  
   }  
   int main() {  
       Base* pbase = new Inherit();  
       Inherit* pInherit = dynamic_cast<Inherit*>(pbase);  
       pInherit->show();//这样动态转换,我们就可以调用派生类的函数了  
       system("Pause");  
       return 0;  
   }

运行结果如下:

   Inherit funtion

3. shared_ptr,weak_ptr应该什么时候用,两个指针如果相互引用,应该哪个用shared_ptr,哪个用weak_ptr

shared_ptr:shared_ptr实现共享式拥有概念。

多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。

共享指针的循环引用计数问题采用weak_ptr指针:

weak_ptr是弱引用,weak_ptr的构造和析构不会引起引用计数的增加或减少。我们可以将其中一个改为weak_ptr指针就可以了。

首先初始化的类采用weak_ptr。


4. 右值具体是怎么实现的,比如string里的右值具体是怎么用的

https://blog.csdn.net/xi_niuniu/article/details/50241227

string里的右值具体实现移动语义

右值引用可以引用并修改右值,但是通常情况下,修改一个临时值是没有意义的。然而在对临时值进行拷贝时,我们可以通过右值引用来将临时值内部的资源移为己用,从而避免了资源的拷贝

实现方法就是移动构造函数,移动构造函数与拷贝构造不同,它并不是重新分配一块新的空间同时将要拷贝的对象复制过来,而是"拿"了过来,将自己的指针指向别人的资源,然后将别人的指针修改为nullptr,这一步很重要,如果不将别人的指针修改为空,那么临时对象析构的时候就会释放掉这个资源,那么就没有“拿”过来。下面这张图可以解释copy和move的区别:

img

所以通过右值引用就可以大大提升程序的效率。


5. 局部函数的static变量具体什么时候分配内存

对于C语言的全局和静态变量,初始化发生在任何代码执行之前,属于编译期初始化。

而C++标准规定:全局或静态对象当且仅当对象首次用到时才进行构造。



以上所有题的答案其实都来源于我的博客面经,欢迎大家围观:https://blog.nowcoder.net/jiangwenbo