字节跳动 C++开发实习 上海 面经

字节跳动C++开发上海实习面经

一面(23号)

时间:大概1h

  • Q: TCP和UDP的区别
    A: TCP是字节流,可靠传输,需要通过三次握手建立连接。UDP是数据报,不可靠且不需要握手。

  • Q: TCP如何实现可靠传输
    A: TCP序列号

  • Q: 那TCP如何用序列号来保证可靠传输
    A: 介绍了下 握手时交换initial sequence number、ACK、超时重传 和 快速重传

  • Q: TCP的滑动窗口与流量控制

  • Q: TCP的拥塞控制
    A: 回答了些常见的拥塞控制算法: tahoe reno cubic bbr

  • Q: 你提到了 快速重传, 能介绍一下 快速重传在拥塞控制中是如何处理的吗

  • Q: 死锁的四个必要条件

  • Q: 举例子讲解如何解决死锁
    A: 从破坏死锁的四个必要条件角度回答。举了自己实现课程Project里,以锁的内存地址为顺序加锁以避免死锁的例子。

  • Q: new 和 malloc 区别
    A: 讲了一下new expression是如何调用operator new、构造函数 和 处理异常的。详细见cppreference - new表达式。malloc的内存只是调用glibc库函数申请一块可用的内存,并没有调用构造函数。而且也不能保证正确的alignment。

  • Q: C++内存管理:std::shared_ptr, std::unique_ptr, std::weak_ptr

  • Q: 除了std::weak_ptr,还有哪些解决循环引用的办法?
    A: 瞎说了一个 可以用解决死锁循环等待的办法,允许循环引用偶尔发生。循环引用较多时,构造系统的资源图,在图中找到环,并破坏这些环。面试管回答说实践中的确有这种办法。

  • Q: 来实现一个unique_ptr吧,不需要自定义的deleter,简单的就可以

编程题:

LC92 翻转链表m到n:个人博客题解。自己写了一个简单的测试用例测试了一下。

写的reverse函数有bug,找了好久,差点翻车。

二面(26号)

时间:大概1h

class A 
{   
private:        
  int a;        
  int b; 
  double c;
public:          
  virtual void f();
};

class B : public A 
{ 
private:     
    double d;     
    char*  e; 
public:     
    void f() {} 
};

B b;
  • Q: 上面这段程序,sizeof(b)为多少
    A: 考虑vptr和对齐,关于x64上的虚函数和虚基类相关的ABI,可以参考Itanium C++ ABI - Chapter 2: Virtual Table Layout

    • B自己的data member:8bytes对齐后为16bytes
    • A自己的data member:8bytes对齐后为16bytes
    • vptr为8bytes,A为B的primary base class,则A和B共享一个vptr
    • 因此总共为16 + 16 + 8 = 40bytes
  • Q: 上面这段程序存在哪些问题?
    A:

    • 当多态地使用derived class B时,如果A的析构函数未声明未虚函数,可能会导致内存泄漏
    • derived class B中的函数void f(){}和基类中的virtual void f()有相同的函数签名,虽然此时会override基类中的virtual void f(),但为了避免函数签名写错而导致错误的声明一个新函数,还是要标上override
  • Q: 讲一下项目吧
    A: 讲了下自己实现的C++20 coroutine + Linux io_uring 的网络库。项目GitHub。鬼扯了这个网络库的几个优点:

    • 使用callback的网络库使业务逻辑割裂,使用coroutine使业务逻辑更清晰
    • io_uring大大减少系统调用的次数,socket的读写都在内核中完成
    • structured concurrency,减少了使用std::shared_ptr的次数,使用C++的RAII即可维护对象的生命周期
    • File I/O 和 socket 可以在同一框架下使用。
  • Q: 除了使用coroutine的异步编程,还知道哪些异步编程的模式呢
    A: 鬼扯了一下C++23的executor模型和Facebook的libunifex

编程题:

类似LC93复原IP地址的题目。给定一个全为数字的字符串,要将字符串分为5个数字,每个数字不能超过600。

彻底翻车,到最后也没调对。

三面(30号)

时间: 大概1h

  • Q: 讲了一下项目
  • 就不问你基础了,之前的面试已经问了很多了,来做一个题吧
  • 提问时间:这个组主要是实现一个浏览器内核,从头造轮子,包括智能指针之类的都是自己实现的。

编程题

实现一个parser,要求能够parse下面这样的串,并返回一个树。要求检查<a></a>这样的标签必须能够对应,不能是<a></aa>

<a>
  <b>
    str
  </b>
  <c>
    <d>
    </d>
  </c>
</a>

面试官人特别好,一直在指导我。这个题要注意new出来的东西在匹配失败的时候别忘了delete。LC里有几个类似这种parser的题,见个人博客 - 设计parser

#实习##面经##C++工程师#
全部评论
学到了,还没做过最后那种编程题
3 回复 分享
发布于 2020-08-31 10:02
最良心的面经了把
1 回复 分享
发布于 2020-08-30 23:09
楼主是应届生吗,感觉让写的挺难得
点赞 回复 分享
发布于 2020-08-30 19:56
大佬好强啊
点赞 回复 分享
发布于 2020-08-30 21:20
点赞 回复 分享
发布于 2020-08-31 08:14
楼主好厉害👍🏿
点赞 回复 分享
发布于 2020-08-31 11:50
太强了
点赞 回复 分享
发布于 2020-09-01 20:23

相关推荐

异步编程是一种编程模式,用于处理可能会花费较长时间的操作,而不会阻塞其他代码的执行。在同步编程中,代码会按照顺序一步一步执行,每个操作的完成都会等待前一个操作完成后才继续执行。这样的执行方式可能会导致程序在等待某些操作完成时出现阻塞,影响用户界面的响应性或导致整个程序的执行速度变慢。异步编程通过将长时间运行的操作(如网络请求、文件读取、数据库查询等)放置在后台,不会阻塞主线程的执行。在进行异步编程时,可以在发起异步操作后继续执行后续的代码,而不需要等待异步操作完成。💦当异步操作完成时,系统会通知相应的回调函数或执行注册的事件处理程序,以便使用异步操作的结果继续处理。💢常见的异步编程模式和技术包括:https://www.nowcoder.com/issue/tutorial?zhuanlanId=Mg58Em&amp;uuid=aa2d7fa706914dfc9afef6476efb3004🔼回调(Callback):&nbsp;将一个函数作为参数传递给异步操作,并在操作完成时调用该函数。这是一种传统的异步编程模式,但它容易造成回调地狱(callback&nbsp;hell)的问题,即多层嵌套的回调函数,难以维护和阅读。🔼Promise:&nbsp;Promise&nbsp;是一种表示异步操作的对象,可以在异步操作完成后进行处理。使用&nbsp;Promise,可以链式地调用&nbsp;then()&nbsp;方法来处理成功的结果,以及&nbsp;catch()&nbsp;方法来处理失败的情况,避免了回调地狱问题。🔼Async/await:&nbsp;Async/await&nbsp;是基于&nbsp;Promise&nbsp;的语法糖,它提供了更加简洁和易读的方式来处理异步操作。通过使用&nbsp;async&nbsp;关键字声明一个函数,并在其中使用&nbsp;await&nbsp;关键字等待异步操作的结果,可以以同步的方式编写异步代码。异步编程使我们能够更好地处理网络请求、文件读写、数据库操作等耗时任务,同时保持应用程序或系统的响应性。它对于处理事件驱动的操作和并发任务非常有用,提高了代码的性能和可维护性。
点赞 评论 收藏
分享
17 135 评论
分享
牛客网
牛客企业服务