• tt
    2019-12-09
    文中下面的一句话:

    “首先是内存分配。如果 new 出错,按照 C++ 的规则,一般会得到异常 bad_alloc,对象的构造也就失败了。这种情况下,在 catch 捕捉到这个异常之前,所有的栈上对象会全部被析构,资源全部被自动清理。”

    谈的是new在分配内存时的错误,是堆上内存的错误,但自动被析构的却是栈上的对象。一开始我想是不是笔误了,但仔细想想,堆上的东西都是由栈上的变量所引用的,栈上对象析构的过程,堆上相应的资源自然就被释放了。而且被释放的对象的范围还被栈帧限定了。
    展开

    作者回复: 对,这就是 RAII,非常重要。

    学习速度飞快啊。👍

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

    作者回复: 我不觉得用异常有什么特别的地方,因而用异常的我个人没觉得有什么特别可参考的。

    由于历史原因,有不少大名气的 C++ 程序没有使用异常,特别是 Google 的项目,比如 Chromium。不用异常,实际上是对用户友好(可执行文件略小,性能有可能有小提升),而对开发者更累。

    我知道用到异常的一些项目:

    - Boost
    - C++ REST SDK
    - pytorch
    - pybind11
    - Armadillo
    - nlohmann/json
    - cppcheck
    - OpenCV
    - LibreOffice

    这篇文章也可以看一下:

    https://cppdepend.com/blog/?p=311

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

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

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

    作者回复: 任何东西用得不好都是坑。有朋友遇到小项目里用了一大堆(不必要的)设计模式,把代码硬生生弄得不可理解。不能说设计模式就是不好,是不?

    MSVC 可以用 ... 捕获非法指针操作,这也是极易被误用的功能。以前也遇到过一次,一不小心用了这个功能,把明明在调试时可以发现的崩溃变成了程序的怪异行为。不过,严格来讲这不属于 C++ 的异常……这实际上是 Windows 的 SEH,纯 C 里都能做得到。

    
     2
  • Encoded Star
    2019-12-22
    一、使用异常
    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。很好!

     1
     1
  • tr
    2020-01-25
    “异常比较隐蔽,不容易看出来哪些地方会发生异常和发生什么异常。”
    老师,一般来说是不是都采用错误码+异常的方式来处理这种问题。接口内部抛出异常并处理异常,对外返回错误码,调用接口的人就不用考虑接口内部抛出的异常?

    作者回复: 如果你要给非C++的本地客户调用,可能得把异常换成错误码。如果是本地C++调用者,或者是可以处理异常的远程客户,使用异常比使用错误码,调用者的代码更简单。

    当然,对于远程调用者,实际上就不能随便抛C++的异常了,必须是事先定义好的明确异常。

    
    
  • tr
    2020-01-24
    老师,为什么vector让operator[]是noexcept,是为了性能么?然后at用来调试?

    作者回复: 应该是,这样也和C数组的[]完全一致,以免有人说,从数组换成vector,性能就下降了……

    
    
  • Terry
    2020-01-22
    如果new失败,抛出异常不处理,程序不会crash吗

    作者回复: 当然会。

    不过,实现上有一个复杂性。在有虚拟内存的操作系统环境里,你通常不会在分配内存时得到异常(除非你要内存是理论上都不可能满足的)。然后,在你实际使用这些内存时,操作系统才会真正分配物理内存。如果你申请的内存太多了,通常会发生的事情并不是你会得到 bad_alloc 异常,而是你的程序莫名其妙地被系统杀死,或者只是系统慢得像蚂蚁爬,你自己都忍受不下去……

    
    
  • 执假以为真
    2020-01-12
    个人所见的年销售额数亿美元产品的工业级代码里确实没见到异常,也许如文中所述的原因及历史原因吧。但有什么知名产品的C++代码或著名开源项目是使用了异常的吗?

    作者回复: 实际上有个评论里我已经回答了。再列一下:

    - Boost
    - C++ REST SDK
    - pytorch
    - pybind11
    - Armadillo
    - nlohmann/json
    - cppcheck
    - OpenCV
    - LibreOffice

    
    
  • 不谈
    2019-12-17
    作为java程序员刚开始对于C++这种规则完全不能理解,看了文章之后又理解了,不使用异常是有道理的。现在理解了vector 会在元素类型没有提供保证不抛异常的移动构造函数的情况下,在移动元素时会使用拷贝构造函数这句话的含义了。C++就是这么与众不同

    作者回复: 这种行为是和值语义密切关联的——和 Java 不同。而且,要在构造函数和运算符重载中表达错误,异常是唯一的方法。

    
    
  • 何敬
    2019-12-13
    请问libbreakpad跟underflow_error有关联么?现在使用breakpad捕获异常,有很多underflow_error的信息

    作者回复: 对不起,我对 libbreakpad 完全不了解。

    
    
  • 何敬
    2019-12-11
    请问underflow_error 什么情况下会抛出?

    作者回复: https://zh.cppreference.com/w/cpp/error/underflow_error

    定义作为异常抛出的类型。它可用于报告算术下溢错误(即计算结果是非正规浮点值的情形)。
    标准库组建不抛此异常(数学函数按指定于 math_errhandling 的方式报告下溢错误)。然而第三方库使用它。例如,若启用了 boost::math::policies::throw_on_error (默认设置),则 boost.math 抛出 std::underflow_error 。

    
    
  • 花晨少年
    2019-12-11
    C++ 虽然支持运算符重载,可你也不能使用,因为你没法返回一个新矩阵……
    不太理解这句话的意思,是用运算符来替换构造函数吗,运算符为啥不能返回新矩阵?

    作者回复: 因为返回值得留给错误码啊……既然不能用异常。

    
    
  • neilyu
    2019-12-10
    C++ 虽然支持运算符重载,可你也不能使用,因为你没法返回一个新矩阵……
    //请问这句话怎么理解?为啥不能返回一个新矩阵呢?

    作者回复: 因为返回值留给错误码了啊……

    
    
  • 李蔚韬
    2019-12-09
    老师,对于异常的第一条批评我不太理解,什么叫“只要开启异常,即使不使用”,这里的开启是指什么呢?

    作者回复: 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);
    }

     4
    
  • 禾桃
    2019-12-09
    “异常处理并不意味着需要写显式的 try 和 catch。异常安全的代码,可以没有任何 try 和 catch。”

    出现异常时,如果没有任何的try catch,只是让std::terminate, 即使没有资源泄漏之类的,感觉什么也做不了了,感觉还是应该要catch,做点啥,至少得记录一下哪抛出异常,什么异常,然后再主动的std::terminate。

    作者回复: 外围(比如main里)当然是要写catch的。(我们一般也不会主动去调terminate;退出的话一般用exit。)但异常安全的代码本身可以没有任何try和catch。

    学得真快。☺️

     1
    
  • 禾桃
    2019-12-09
    happy path—-> hot path:)

    作者回复: 不是,就是happy path。愉快的(乐观情况下的)执行路径,而不是说是否频繁。

    
    
我们在线,来聊聊吧