news 2026/7/15 4:57:43

异常处理try/catch:面试官问“机器人程序崩了怎么办“,我这样答直接加分

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
异常处理try/catch:面试官问“机器人程序崩了怎么办“,我这样答直接加分

上篇聊了模板类,C++基础语法部分到这里基本收尾了。今天讲一个工程味很浓的话题——异常处理。

异常处理在面试里不算高频考点,但一旦问到,区分度很大。因为大部分人只会写try/catch,但对异常的安全机制、性能影响、最佳实践说不清楚。

讲个真实场景。

机器人跑着跑着,激光雷达突然断连了。如果没有异常处理,程序可能直接崩溃——指针解引用一个空数据,段错误,core dump。整个机器人停在那里,一动不动。

有了异常处理,你可以优雅地降级:检测到传感器断连,抛异常,上层捕获,切换到备用传感器或者安全停车。

这就是异常处理在机器人开发里的意义——不是让程序不犯错,而是让程序犯错的时候不会死。

try/catch的基本用法

语法很简单:

try { // 可能出错的代码 double distance = readLidar(); if (distance < 0) { throw runtime_error("Lidar reading error: negative distance"); } processDistance(distance); } catch (const runtime_error& e) { // 处理runtime_error cerr << "Error: " << e.what() << endl; useFallbackSensor(); } catch (const exception& e) { // 处理其他标准异常 cerr << "Unexpected error: " << e.what() << endl; } catch (...) { // 兜底:捕获所有异常 cerr << "Unknown error!" << endl; emergencyStop(); }

几个要点:

catch的顺序很重要。子类异常要放在前面,父类异常放在后面。因为catch是按顺序匹配的,一旦匹配到就不再往下走。如果把exception放最前面,它会捕获所有标准异常,后面的catch就永远不会执行了。

catch(...)是兜底,捕获所有异常,包括非标准异常。但它的缺点是你拿不到任何异常信息。

异常类继承体系

C++标准库定义了一套异常类层次:

exception ├── logic_error │ ├── invalid_argument │ ├── out_of_range │ └── length_error └── runtime_error ├── range_error ├── overflow_error └── system_error

面试偶尔会让你区分logic_error和runtime_error。简单说:logic_error是逻辑错误,理论上可以通过代码检查避免(比如参数越界);runtime_error是运行时错误,只有在程序跑起来之后才能发现(比如硬件故障)。

在机器人开发里,自定义异常类通常继承自runtime_error:

class SensorException : public runtime_error { string sensor_name_; int error_code_; public: SensorException(const string& name, int code) : runtime_error("Sensor " + name + " error: " + to_string(code)), sensor_name_(name), error_code_(code) {} const string& sensorName() const { return sensor_name_; } int errorCode() const { return error_code_; } }; // 使用 try { throw SensorException("lidar_front", 1001); } catch (const SensorException& e) { cerr << e.what() << endl; cerr << "Sensor: " << e.sensorName() << endl; // 可以根据error_code做不同处理 }

这样做的优点是异常信息丰富——你知道是哪个传感器出了什么问题,方便定位和恢复。

异常安全:机器人开发里的关键问题

面试官如果深挖,会问"什么是异常安全"。

异常安全有三个等级。

基本保证:程序在抛异常后不会泄漏资源。比如new了一块内存,在异常路径上也能释放。

强保证:异常发生后,程序状态回滚到调用前的状态。要么完全成功,要么什么都不变。

不抛异常保证:函数保证不抛异常。用noexcept关键字标记。

void processData() noexcept { // 保证不抛异常 // 如果真抛了,程序直接terminate }

在机器人开发里,运动控制相关的函数通常标记为noexcept。因为机器人正在走的时候,你不能用异常来处理错误——你得用返回值或者状态码,确保控制回路不会被打断。

异常的争议:用还是不用

讲真,C++社区对异常的态度是分裂的。

Google的C++编码规范里明确禁止使用异常。理由是:异常的性能开销不可预测,而且大型项目里异常会让控制流变得很难追踪。

但很多机器人框架(包括ROS)是依赖异常的。比如PCL的IO操作、Eigen的部分运算,出错了就抛异常。你不用异常,就得在每层都检查返回值,代码写起来很啰嗦。

讲个实际例子。我之前做一个导航模块的时候,初始化阶段用了大量异常处理——加载地图文件可能失败、连接激光雷达可能超时、读取配置文件可能格式错误。这些都是一次性的操作,用异常处理很合适。但在主控制循环里,所有错误都用返回值处理,因为控制循环跑100Hz,你不能让它因为异常被中断。

我的建议是:在机器人开发里,异常适合处理"不太可能发生的错误"——比如硬件初始化失败、配置文件格式错误。对于"经常发生的错误"——比如传感器读数偶尔超时——用返回值更合适。

记住一个原则:异常处理的是"异常"情况,不是"正常"的错误流程。

面试中的异常考点

面试官考异常,几个经典问题。

"异常和错误码相比有什么优缺点?"优点是异常不能忽略(你不catch就往上抛,最终程序崩溃,逼着你处理);缺点是影响性能、让控制流不直观。

"析构函数能抛异常吗?"最好不要。如果析构函数在栈展开过程中抛异常,程序会直接terminate。这就是为什么析构函数通常标记为noexcept。

"catch的时候用值还是引用?"用const引用。用值会多一次拷贝,而且可能发生对象切片(slicing)——子类异常被截成父类。

还有一个面试深度追问:异常安全的三个保证级别你知道吗?第一层是基本保证——即使抛出异常,程序的状态也是合法的,没有资源泄漏,但数据可能变了。第二层是强保证——操作要么成功要么完全回滚,就像数据库的事务一样,数据状态不变。第三层是无异常保证——函数承诺绝不抛出异常,也就是noexcept。在机器人开发里,控制指令的发送函数一般要做到强保证,因为发了一半的指令比不发更危险。实现异常安全最靠谱的方法还是RAII——用智能指针和局部对象来管理资源,让析构函数自动清理,这样即使中途抛异常也不会泄漏。面试时能讲出异常安全的三个级别,再结合RAII给出解决方案,面试官基本就满意了。

给正在准备面试的你一点建议

异常处理在面试里不算高频,但属于"会了加分"的知识点。

记住三点就够了:try/catch的基本语法和catch顺序,自定义异常类的设计,异常安全的基本概念。

如果你能聊到"Google为什么禁用异常"以及"机器人开发里异常和返回值的选择",面试官会觉得你有工程思维,不只是会写代码。

再聊一个面试常考的延伸点:noexcept关键字。C++11引入了noexcept,让你可以标记一个函数不会抛出异常。比如移动构造函数通常标记为noexcept,因为STL容器在扩容时会优先选择noexcept的移动构造而不是可能抛异常的拷贝构造,这对性能影响很大。如果你能在面试中解释"为什么移动构造函数要标记noexcept",面试官会觉得你对异常安全和性能优化都有理解。

下篇讲命名空间——大型项目中避免冲突的规范。


如果这篇文章对你有帮助,欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。

「机器人软件开发面试·从入门到精通」连载系列上一篇:第27篇 模板类——STL容器的底层设计思路 下一篇预告:第29篇 命名空间——大型项目中避免冲突的规范

有任何问题欢迎评论区留言,我会尽量回复。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/15 4:57:08

STL之list与deque:不同场景下的容器选型,别再无脑用vector了

上篇把vector扒了个底朝天&#xff0c;今天看它的两个"兄弟"——list和deque。面试里经常这样问&#xff1a;"vector和list有什么区别&#xff1f;什么时候用哪个&#xff1f;"这个问题看起来基础&#xff0c;但真能答好的人不多。很多人背了一句"vec…

作者头像 李华
网站建设 2026/7/15 4:57:04

Davinci Developer的Constants

常量,这东西是用来给data type关联无效值用的 新建操作 New Textual Constant 字符串或者二进制数据

作者头像 李华
网站建设 2026/7/15 4:56:55

Python图形匹配实战:从PyAutoGUI到OpenCV的窗体自动化解决方案

1. 项目概述&#xff1a;为什么我们需要图形匹配&#xff1f;如果你做过桌面自动化&#xff0c;肯定遇到过这样的场景&#xff1a;你想让程序自动点击某个按钮&#xff0c;但这个按钮的位置每次启动软件都可能不一样&#xff0c;或者它的窗口大小、DPI缩放一变&#xff0c;你之…

作者头像 李华
网站建设 2026/7/15 4:56:14

大疆嵌入式笔试核心考点与实战解析

1. 大疆嵌入式笔试概述大疆作为全球领先的无人机和智能硬件公司&#xff0c;其嵌入式岗位笔试以考察范围广、题目难度高著称。根据历年考生反馈&#xff0c;笔试通常包含20道单选、10道多选、10道判断和2道编程题&#xff0c;限时90分钟完成。这种高强度设计不仅测试知识储备&a…

作者头像 李华
网站建设 2026/7/15 4:53:27

ComfyUI-deepgpu插件:AI图像生成加速80%的技术原理与实践

如果你正在使用ComfyUI进行AI图像或视频生成&#xff0c;一定遇到过这样的困扰&#xff1a;生成一张高质量图片需要几十秒甚至几分钟&#xff0c;调整参数后又要重新等待&#xff0c;创作效率被硬件性能严重制约。特别是在迭代调试工作流时&#xff0c;漫长的等待时间让创意过程…

作者头像 李华
网站建设 2026/7/15 4:53:20

C语言 超详细 零基础入门 共用体(union)与typedef的实战应用与内存解析

1. 共用体(union)的本质与内存布局共用体是C语言中一种特殊的数据结构&#xff0c;它允许在同一块内存区域存储不同类型的数据。想象你有一个收纳盒&#xff0c;这个盒子可以放一本书、一个水杯或者一台笔记本电脑&#xff0c;但同一时间只能放其中一样东西——共用体就是这样的…

作者头像 李华