作者回复: 对,这就是 RAII,非常重要。
学习速度飞快啊。👍
作者回复: 我不觉得用异常有什么特别的地方,因而用异常的我个人没觉得有什么特别可参考的。
由于历史原因,有不少大名气的 C++ 程序没有使用异常,特别是 Google 的项目,比如 Chromium。不用异常,实际上是对用户友好(可执行文件略小,性能有可能有小提升),而对开发者更累。
我知道用到异常的一些项目:
- Boost
- C++ REST SDK
- pytorch
- pybind11
- Armadillo
- nlohmann/json
- cppcheck
- OpenCV
- LibreOffice
这篇文章也可以看一下:
https://cppdepend.com/blog/?p=311
作者回复: 网络就看 Boost.Asio 吧。这个将是未来 C++ 网络标准库的基础。
作者回复: 任何东西用得不好都是坑。有朋友遇到小项目里用了一大堆(不必要的)设计模式,把代码硬生生弄得不可理解。不能说设计模式就是不好,是不?
MSVC 可以用 ... 捕获非法指针操作,这也是极易被误用的功能。以前也遇到过一次,一不小心用了这个功能,把明明在调试时可以发现的崩溃变成了程序的怪异行为。不过,严格来讲这不属于 C++ 的异常……这实际上是 Windows 的 SEH,纯 C 里都能做得到。
作者回复: OK。很好!
作者回复: 如果你要给非C++的本地客户调用,可能得把异常换成错误码。如果是本地C++调用者,或者是可以处理异常的远程客户,使用异常比使用错误码,调用者的代码更简单。
当然,对于远程调用者,实际上就不能随便抛C++的异常了,必须是事先定义好的明确异常。
作者回复: 应该是,这样也和C数组的[]完全一致,以免有人说,从数组换成vector,性能就下降了……
作者回复: 当然会。
不过,实现上有一个复杂性。在有虚拟内存的操作系统环境里,你通常不会在分配内存时得到异常(除非你要内存是理论上都不可能满足的)。然后,在你实际使用这些内存时,操作系统才会真正分配物理内存。如果你申请的内存太多了,通常会发生的事情并不是你会得到 bad_alloc 异常,而是你的程序莫名其妙地被系统杀死,或者只是系统慢得像蚂蚁爬,你自己都忍受不下去……
作者回复: 实际上有个评论里我已经回答了。再列一下:
- Boost
- C++ REST SDK
- pytorch
- pybind11
- Armadillo
- nlohmann/json
- cppcheck
- OpenCV
- LibreOffice
作者回复: 这种行为是和值语义密切关联的——和 Java 不同。而且,要在构造函数和运算符重载中表达错误,异常是唯一的方法。
作者回复: 对不起,我对 libbreakpad 完全不了解。
作者回复: https://zh.cppreference.com/w/cpp/error/underflow_error
定义作为异常抛出的类型。它可用于报告算术下溢错误(即计算结果是非正规浮点值的情形)。
标准库组建不抛此异常(数学函数按指定于 math_errhandling 的方式报告下溢错误)。然而第三方库使用它。例如,若启用了 boost::math::policies::throw_on_error (默认设置),则 boost.math 抛出 std::underflow_error 。
作者回复: 因为返回值得留给错误码啊……既然不能用异常。
作者回复: 因为返回值留给错误码了啊……
作者回复: GCC/Clang 下的 -fexceptions(缺省开启),MSVC 下的 /EHsc(我要求大家需要用的,Visual Studio 项目里也会自动用)。
我刚试了,用 GCC,加上 -fno-exceptions 命令行参数,对于下面这样的小程序,也能看到产生的可执行文件的大小的变化。
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5};
v.push_back(20);
}
作者回复: 外围(比如main里)当然是要写catch的。(我们一般也不会主动去调terminate;退出的话一般用exit。)但异常安全的代码本身可以没有任何try和catch。
学得真快。☺️
作者回复: 不是,就是happy path。愉快的(乐观情况下的)执行路径,而不是说是否频繁。