现代 C++ 编程实战
吴咏炜
前 Intel 资深软件架构师
34196 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
加餐 (1讲)
现代 C++ 编程实战
15
15
1.0x
00:00/00:00
登录|注册

06 | 异常:用还是不用,这是个问题

性能
可执行文件大小
使用assert
使用异常
cppreference.com, “std::exception”
cppreference.com, “Exceptions”
FAQ—exceptions and error handling
LLVM coding standards
Discussion on “Examples of C++ projects which embrace exceptions?”
Google C++ style guide
原因讨论
项目中是否使用异常
推荐正确使用异常的便捷错误处理机制
异常的优势和使用方式
异常的使用示例
异常的处理方式
异常安全性保证
异常安全的代码
使用异常的优势
C++中不使用异常的问题
C语言中的错误处理
其他项目禁用异常的原因
Google的历史原因
Google禁用异常的原因
Google的C++风格指南
异常在调试和发布模式下的效果
逻辑错误处理方式的选择
标准库的错误处理方式
异常的代价
异常的隐蔽性
异常违反了C++原则
异常的便利性
逻辑错误处理方式的选择
C++标准库的错误处理方式
参考资料
课后思考
内容小结
使用异常
没有异常的世界
避免异常的风格指南
使用异常的理由
异常的问题
为什么使用异常
异常处理方式

该思维导图由 AI 生成,仅供参考

你好,我是吴咏炜。
到现在为止,我们已经有好多次都提到异常了。今天,我们就来彻底地聊一聊异常。
首先,开宗明义,如果你不知道到底该不该用异常的话,那答案就是该用。如果你需要避免使用异常,原因必须是你有明确的需要避免使用异常的理由。
下面我们就开始说说异常。

没有异常的世界

我们先来看看没有异常的世界是什么样子的。最典型的情况就是 C 了。
假设我们要做一些矩阵的操作,定义了下面这个矩阵的数据结构:
typedef struct {
float* data;
size_t nrows;
size_t ncols;
} matrix;
我们至少需要有初始化和清理的代码:
enum matrix_err_code {
MATRIX_SUCCESS,
MATRIX_ERR_MEMORY_INSUFFICIENT,
};
int matrix_alloc(matrix* ptr,
size_t nrows,
size_t ncols)
{
size_t size =
nrows * ncols * sizeof(float);
float* data = malloc(size);
if (data == NULL) {
return MATRIX_ERR_MEMORY_INSUFFICIENT;
}
ptr->data = data;
ptr->nrows = nrows;
ptr->ncols = ncols;
}
void matrix_dealloc(matrix* ptr)
{
if (ptr->data == NULL) {
return;
}
free(ptr->data);
ptr->data = NULL;
ptr->nrows = 0;
ptr->ncols = 0;
}
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

异常处理在C++中是一个备受关注的话题。本文首先介绍了异常处理的优势,指出使用异常能够简化代码结构,使得代码更加简洁和清晰。然后,文章讨论了一些大型项目禁用异常的原因,包括历史原因、性能问题以及对二进制文件大小和性能的追求。接着,文章提到了在特定项目中禁用异常可能是必要的,但对于一般项目来说,使用异常能够提高代码的可读性和可维护性。此外,文章还介绍了C++中异常的一些批评,包括异常违反了C++原则以及异常比较隐蔽的问题。最后,文章总结了使用异常的理由和不使用异常的理由,强调异常是C++中的标准错误处理方式,并提出了一些使用异常的建议。通过对比使用异常和不使用异常的代码示例,以及大型项目禁用异常的原因,全面地介绍了异常处理在软件开发中的重要性和实际应用情况。 总的来说,本文深入探讨了C++中异常处理的优势、禁用异常的原因以及使用异常的建议,为读者提供了全面的异常处理知识和实际应用情况,对于C++开发者来说具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《现代 C++ 编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(32)

  • 最新
  • 精选
  • tt
    文中下面的一句话: “首先是内存分配。如果 new 出错,按照 C++ 的规则,一般会得到异常 bad_alloc,对象的构造也就失败了。这种情况下,在 catch 捕捉到这个异常之前,所有的栈上对象会全部被析构,资源全部被自动清理。” 谈的是new在分配内存时的错误,是堆上内存的错误,但自动被析构的却是栈上的对象。一开始我想是不是笔误了,但仔细想想,堆上的东西都是由栈上的变量所引用的,栈上对象析构的过程,堆上相应的资源自然就被释放了。而且被释放的对象的范围还被栈帧限定了。

    作者回复: 对,这就是 RAII,非常重要。 学习速度飞快啊。👍

    2019-12-09
    5
    37
  • 看到老师说了部分开源的异常优秀的C++开源项目,老师能否推荐些现在流行的,能逐步深入的网络编程方面的C++开源项目看呢,从入门到深入的都推荐一些吧。谢谢老师

    作者回复: 网络就看 Boost.Asio 吧。这个将是未来 C++ 网络标准库的基础。

    2019-12-17
    29
  • tokamak
    老师,你好。目前主流的开源项目中,有没有使用了异常的优秀的C++开源项目?可以用来作为参考案例。

    作者回复: 我不觉得用异常有什么特别的地方,因而用异常的我个人没觉得有什么特别可参考的。 由于历史原因,有不少大名气的 C++ 程序没有使用异常,特别是 Google 的项目,比如 Chromium。不用异常,实际上是对用户友好(可执行文件略小,性能有可能有小提升),而对开发者更累。 我知道用到异常的一些项目: - Boost - C++ REST SDK - pytorch - pybind11 - Armadillo - nlohmann/json - cppcheck - OpenCV - LibreOffice 这篇文章也可以看一下: https://cppdepend.com/blog/?p=311

    2019-12-13
    21
  • fl260919784
    老师好,有没有编译器平台对异常的实现原理的资料呢,比如X86下G++ -S会发现安插了一些__cxa_throw之类的调用,感谢

    作者回复: 可以参考下面这些链接: http://baiy.cn/doc/cpp/inside_exception.htm https://gcc.gnu.org/wiki/Dwarf2EHNewbiesHowto https://stackoverflow.com/questions/15670169/what-is-difference-between-sjlj-vs-dwarf-vs-seh

    2020-02-17
    6
  • EncodedStar
    一、使用异常 1.异常处理并不意味着需要写显示的try和catch。异常安全的代码,可以没有任何try和catch 2.适当组织好代码,利用好RAII,实现矩阵的代码和使用矩阵的代码都可以更短、更清晰,处理异常一般情况会记日志或者向外界用户报告错误。 二、使用异常的理由 1.vector C++标准容器中提供了at成员函数,能够在下标不存在的时候抛出异常(out_of_range),作为一种额外的帮助调试手段 2.强异常保证,就是一旦异常发生,现场会恢复到调用异常之前的状态。(vector在元素类型没有提供保证不抛异常的移动构造函数的情况下,在移动元素时会使用拷贝构造函数,一旦某操作发生异常,就可以恢复原来的样子) 3.只要使用标准容器就都的处理可能引发的异常bad_alloc 4。可以使用异常,也可以使用assert 课后思考 你的C++项目里使用过异常吗?为什么? 答:按老师课里说的,只要使用了标准容器就得考虑使用处理异常(bad_alloc),所以,大部分C++代码如果保证安全的情况下都的考虑这个异常。当然也在别的地方,之前在读取配置文件(json文件)字段的时候加过,如果读取失败,异常抛出

    作者回复: OK。很好!

    2019-12-22
    2
    5
  • 怪兽
    异常真是一个大话题,请假老师2个疑问点: 1. 函数标不标noexcept有什么区别?标了noexcept,表示不会抛出异常,也就表示异常安全吗?异常安全的代码也就不需要try和catch了 。但实际上,不管函数有没有标noexcept,如果确实抛出了异常,就会调用std::terminate。所以总的来说,函数标了noexcept只是一种声明而已,是想告诉编译器它是安全的,可以被move或其他优化,老师这样理解对吗? 2. 看评论说,析构函数缺省就是noexcept,那么构造函数缺省也是noexcept的吗?有必要标noexcept吗?

    作者回复: 1. 对。标 noexcept 是一种契约声明,表明该函数永远不应该抛异常,提供不抛异常保证,比强异常安全保证更强。 2. 只有析构函数默认有 noexcept 声明(前提是所有的基类和成员变量的析构函数都 noexcept)。构造函数函数如果不是 default 声明的话,仍需手工标 noexcept。

    2021-06-09
    4
  • 中年男子
    用到异常的时候倒不是很多,但是异常千万别乱用,害人害己, 曾经同事离职,接手他项目的代码,把我坑的,几乎所有能引起crash的地方都用try catch 捕获异常,然而不处理异常,比如非法指针, 这种bug居然用try catch 来规避,坑了我两个月时间才把程序搞稳定了,现在想起他来,心里还有一句mmp想送给他。。。

    作者回复: 任何东西用得不好都是坑。有朋友遇到小项目里用了一大堆(不必要的)设计模式,把代码硬生生弄得不可理解。不能说设计模式就是不好,是不? MSVC 可以用 ... 捕获非法指针操作,这也是极易被误用的功能。以前也遇到过一次,一不小心用了这个功能,把明明在调试时可以发现的崩溃变成了程序的怪异行为。不过,严格来讲这不属于 C++ 的异常……这实际上是 Windows 的 SEH,纯 C 里都能做得到。

    2019-12-09
    3
    4
  • 林林
    为什么说“异常处理并不意味着需要写显式的 try 和 catch” 没有catch的话,程序不是会挂掉吗?

    作者回复: 是的,没有catch,程序会挂掉。但你需要写出 try 和 catch 的地方很少。很多地方的异常处理,就是让程序优雅地通过异常退出当前函数。 就像我文中描述的“matrix c = a * b;”这句可能出异常的地方有好几处,目前的代码写法,也在某种意义上“处理”了异常——确保发生异常时程序行为的完全正常,即给出了异常安全保证。 又如异常安全的代码,常常是让会抛异常的操作最先做(如内存分配),然后再做其他不会抛异常的操作。这样的代码,一般不需要写 try... catch,也同样能在异常情况执行正确的流程。 这和 Java 这样的在编译期进行大量异常检查的语言不一样。在 Java 里,因为检查性异常(checked exception)的使用,你通常会需要写出多得多的 try...catch 语句。

    2021-03-26
    3
  • 怪兽
    老师打扰一下,请教2点疑惑: 1. 原文中描述:“C++ 的标准容器在大部分情况下提供了强异常保证,即,一旦异常发生,现场会恢复到调用函数之前的状态,容器的内容不会发生改变,也没有任何资源泄漏。” 既然是强异常保证下发生异常,此时不就立即调用std::terminate结束程序了?还需要在意现场有没有恢复?容器的内容有没有发生变化? 2. 原文中描述:“只要你使用了标准容器,不管你自己用不用异常,你都得处理标准容器可能引发的异常——至少有 bad_alloc” 这应该是容器在分配内存时,并不是异常安全的,才会抛出的bad_alloc异常吧?如果分配内存是异常安全的,当发生异常抛出bad_alloc时,就立即std::terminate结束程序了,这样理解对吗?

    作者回复: 1. 强异常安全保证不是无异常保证,只是说发生异常时保证还原现场,对象不发生变化。 2. 基本同上。你似乎把异常安全和noexcept保证混淆了。 异常安全有四级: 不抛异常(noexcept)保证 强异常安全保证 基本安全异常保证 没有任何保证

    2021-09-18
    2
  • Minghao
    你好老师,学习了06异常和07迭代器,也自己写了一遍smart_pointer和istream_line_reader。您在课中提到了 “vector 会在元素类型没有提供保证不抛异常的移动构造函数的情况下,在移动元素时会使用拷贝构造函数“。我想请教一下,在自己开发的过程中,一般哪些成员函数需要考虑添加noexcept关键字呢?

    作者回复: 最主要是移动构造函数、移动赋值函数和 swap。析构函数也不应该抛异常,但不用标,缺省就是 noexcept。其他函数,能确保没问题的也标一下,特别是很小的返回引用和指针的函数。

    2020-05-27
    2
收起评论
显示
设置
留言
32
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部