c++开发面试题

本文探讨了CMake作为跨平台编译工具与Makefile在工程编译规则中的应用,比较了两者优势,并深入解析了递归与迭代的区别,以及智能指针在内存管理中的作用。还介绍了HTTP缓存策略和野指针的概念,以及TCP可靠性的保证措施。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.自述项目
2.cmake和makefile区别

makefile

Makefile描述了整个工程的编译、连接等规则,makefile定义了一些列规则来指定,哪些文件需要编译以及如何编译、需要创建哪些库文件以及如 何创建这些库文件、如何产生我们想要的可执行文件。使用Makefile,整个工程都可以完全自动化编译。而且Makefile 可以有效的减少编译和连接的程序,只编译和连接那些修改的文件。

cmake

CMake是一个夸平台的安装(编译)工具,可以简单的语句描述所有平台的安装(编译过程)。它能输出各种各样的makefile或者project文件,能测试编译器所支持的c++特性。

3.leetcode题目,做完之后问优化思路?
迭代和递归的区别,优劣
递归的优点:
代码简洁
优秀的运行速度
以及代码简洁带来的程序的易维护性
递归的缺点:
函数的调用势必带来出栈入栈的操作,递归次数增多随之会带来的是内存的消耗增加
代码的过于简洁,会带来程序的理解问题而七拐八拐的函数调用也不利于代码理解
迭代的优点:
相对递归来说较少的内存占用
优秀的执行速度
相对于递归来说其实更容易理解
这一点指的是,相对于递归来说,迭代的代码执行流程相对来说更加的通俗易懂,迭代的代码不包含各种匪夷所思的函数调用,跳转和返回值所带来的困惑,程序流程较为通俗
迭代的缺点:
-代码的过于依赖循环和判断等结构,势必导致代码的行数增加,随之而来的便是程序的难以理解,复杂晦涩。
记得有人说过,递归能做的,其实迭代都能做,而且有些情况下,迭代由于没有函数的入栈出栈,占用的内存要少于递归这个方式,但是同时并没有什么执行速度的差别,因此迭代是优于递归的我觉得这个说法其实不尽然。
4.智能指针
-简述智能指针
一共有四种,分别是auto_ptr、unique_ptr、shared_ptr和weak_ptr。
在C++11中,auto_ptr被废弃掉,取而代之的是独占指针。同时shaerd_ptr和weak_ptr是一起使用的,防止循环依赖的产生,使得shared_ptr得不到释放。
–为什么要使用智能指针
智能指针如何实现?
所谓智能指针,其实就是一个指针类,使用了智能指针之后,当指针的生命周期结束时,会自动调用析构函数释放内存资源,防止内存泄漏。

智能指针解决了什么问题?
当我们使用new在堆区创建了内存地址时,有时会忘记使用delete去释放内存,容易造成内存泄漏,而使用智能指针的话,它会自动调用析构函数去释放堆区的资源,从而防止内存泄漏。

实践中如何选择智能指针?
如果需要多个指向同一个对象的指针,则可以使用共享指针;反之则选择独占指针
----为什么智能指针可以像普通指针那样使用?
因为其里面重载了 * 和 -> 运算符, * 返回普通对象,而 -> 返回指针对象。
5.HTTP协议的缓存策略有哪些?
HTTP协议的缓存策略有两种,分别是强制缓存和协商缓存,强制缓存的优先级大于协商缓存。
强制缓存是服务器告诉浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行协商缓存策略。
协商缓存是让客户端与服务器之间能实现缓存文件是否更新的验证、提升缓存的复用率,将缓存信息中的Etag和Last-Modified字段通过请求发送给服务器,由服务器校验。如果文件没有改变,那么直接返回304状态,继续使用浏览器缓存。
加分回答

HTTP协议的缓存策略是浏览器每次发起请求时,先在本地缓存中查找结果以及缓存标识,根据缓存标识来判断是否使用本地缓存。如果缓存有效,则使用本地缓存,否则,则向服务器发起请求并携带缓存标识。HTTP协议的缓存策略分两种:强制缓存和协商缓存,而强制缓存优先级大于协商缓存。

强制缓存:服务器告诉浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
协商缓存:让客户端与服务器之间能实现缓存文件是否更新的验证、提升缓存的复用率,将缓存信息中的Etag和Last-Modified
通过请求发送给服务器,由服务器校验。如果文件没有改变,那么直接返回304状态,继续使用浏览器缓存。
HTTP缓存都是从第二次请求开始的:

第一次请求资源时,服务器返回资源,并在响应头首部中回传资源的缓存策略。
第二次请求时,浏览器判断这些请求参数,击中强缓存就直接返回状态码200,否则就把请求参数加到请求头首部中传给服务器,看是否击中协商缓存,击中则返回304,否则服务器会返回新的资源。
6.什么是野指针
概念:野指针也就是指向位置不可知的指针
产生原因:释放内存后,指针没有及时置空,仍然指向该内存

===========
三次握手
1.客户端发送一个SYN包给服务器端,客户端由closed状态进入SYN-SENT状态。
2.服务器接收到客户端发送的SYN包之后,会发送给客户端一个ACK确认和SYN包。服务器由listen进入syn-received状态
3.客户端接收到服务器端的包之后,回复给服务器端一个ack包。客户端进入establish状态
4.服务器收到ack后进入establish状态。
三次握手建立完成

四次挥手
1.客户端主动关闭连接,发送fin给服务器端。此时客户端不能发送信息,但是还可以接受信息。客户端进入fin-wait1状态
2.服务器收到客户端发来的fin包之后,首先回一个ack,此时等待服务器传输完成没有传输完的数据给客户端,服务器变为close-wait状态
客户端收到后状态变成fin-wait2
3.传输完成后服务器在此发送fin包给客户端,服务器进入last-lock状态
4客户端接收发送一个ack给服务器。客户端进入time-wait状态。并且等待2msl的时间之后close。服务器收到ack后进入close状态。

为什么要等待2msl时间
所谓的msl(max segment lisfetime) 最大报文段生存时间,2msl即是两倍的msl时间,在三次挥手后进行第四次挥手客户端发送一个ACK后进入了time-wait状态,此时要等待2msl时间。原因是担心对方未收到最后的ack包要进行超时重传,此时对方重新发送三次挥手是时候的fin包。
在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

说说 TCP 可靠性保证
crc校验、序列号/确认、超时重传、最大消息长度、滑动窗口、流量控制

c++重载发生在同一个类中,函数同名形参不同
函数重写发生在父子类之间,子类对父类的同名函数进行了重写。同名函数的返回值形参也必须相同

socket
bind
listen
accept
read、write
close

socket
bind
connect
send recv
close

物理层
数据链路层
网络层
传输层
会话层
表示层
应用层

应用层
传输层 tcp/udp
网络层 IP, ICMP, ARP, RARP, AKP, UUCP
网络接口层

### C++ 开发面试题整理 以下是基于提供的引用内容以及专业知识,总结的一些常见 C++ 开发相关的面试题目: #### 1. 虚函数的意义及基类析构函数为何要声明为虚函数? 在继承体系中,如果子类重写了父类的方法,则通过基类指针调用该方法时,实际执行的是派生类中的实现版本。为了支持这种多态行为,C++ 提供了虚函数机制[^1]。 当一个对象通过其基类指针销毁时,如果没有将基类的析构函数定义为 `virtual`,则只会调用基类的析构函数而不会调用派生类的析构函数,这可能导致资源泄漏或其他未定义行为。因此,通常建议将基类的析构函数声明为虚函数以确保安全释放资源。 #### 2. 右值的概念及其应用场景 右值是指那些不能对其取地址的操作数,通常是临时对象或表达式的计算结果。例如,在赋值语句 `int a = b + c;` 中,`b + c` 是一个右值,因为它是一个临时计算的结果,并且在其生命周期结束前不可持久化存储[^2]。 现代 C++ 引入了移动语义和完美转发来优化右值处理过程,从而减少不必要的深拷贝操作并提高程序性能。 #### 3. 表达式效率比较:`x=x+1`, `x+=1`, 和 `x++` 三种写法虽然最终效果相同,但在底层实现上存在差异: - **`x=x+1`:** 创建了一个中间变量用于保存加法运算结果后再将其赋给原变量; - **`x+=1`:** 不创建额外的临时变量直接完成累加动作; - **`x++`:** 对于内置数据类型来说最高效;但对于自定义复杂结构体或者容器而言可能会触发更多内部逻辑因而未必总是最优解。 综上所述,在大多数情况下,对于简单数值类型的增量更新推荐优先考虑使用后缀形式(`x++`) 或者复合赋值语法 (`x += 1`) 来代替显式重新分配整个新值的方式(`x = x + 1`) ,因为它们往往能带来更好的运行速度表现。 #### 4. 关于常量成员函数(const member function) 在一个类里标记某个方法为const意味着这个方法承诺它不会更改任何属于当前实例的状态信息(即非静态字段),即使这些字段本身是非constant属性也一样受到保护约束条件限制不得随意篡改 。下面例子展示了如何正确编写这样的限定版功能代码片段: ```cpp class MyClass { int value; public: void func() const { /* 此处无法修改value */ } }; ``` 上述示例表明即便`MyClass::func()`访问到了私有整型成员`value`但由于自身被设定成只读模式所以尝试对其进行任何形式上的变更都会引发编译错误提示[^3]. #### 5. Vector 的工作原理与注意事项 标准模板库(STL)里的vector是一种能够自动调整容量大小的一维数组抽象表示形式, 它允许随机存取任意位置元素的同时还具备动态扩展能力满足不断增长的需求场景需求. 每当向已满载状态下的vector追加新项目时便会触发动态内存再分配流程: 新开辟一段更大规模区域存放现有全部条目加上新增部分然后再废弃掉原先占用的小范围区间 . 具体扩增比例依据不同平台环境有所不同比如Visual Studio采用约等于原始尺寸乘以因子1.5倍策略而GNU Compiler Collection(GCC)/Clang遵循双倍原则即每次扩充至先前长度两倍那么大.[^4] 此外值得注意的是尽管物理层面上看似腾出了多余空白地带但实际上这部分并未真正归还操作系统依旧归属于对应vector实体直至明确指示清理回收为止. --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值