• C++ 异常处理 重新throw变量时的事件


    直接说结论:throw的表达式创建出来的变量会被拷贝下来【通过拷贝构造函数,后面会证实这一点,且是放在堆里的】,然后沿着调用路径去搜索最近匹配异常的catch语句,在沿途,传递给catch语句的是堆中的异常变量的拷贝;

    下面来证明一件事:

    1:异常的传递是靠拷贝进行的。

    看代码:

    1. #include
    2. #include
    3. using namespace std;
    4. class m_exception :public exception {
    5. public:
    6. m_exception(const char* message)
    7. :exception(message){
    8. cout << this << endl;
    9. }
    10. void printAddress() {
    11. cout << this << endl;
    12. }
    13. ~m_exception() {}
    14. };
    15. void f() {
    16. m_exception e= m_exception("e");
    17. throw e;
    18. }
    19. void g() {
    20. try {
    21. f();
    22. }
    23. catch (m_exception e) {
    24. e.printAddress();
    25. throw;
    26. }
    27. }
    28. int main() {
    29. try {
    30. g();
    31. }
    32. catch (m_exception e) {
    33. e.printAddress();
    34. }
    35. }

    运行结果:

     可以看见,每个catch语句中的变量地址都是不同的,所以这能说明传递异常的方式是拷贝。

    如果我们是将拷贝构造函数delete掉的话:

    m_exception(const m_exception e) = delete;

    编译器就会报错:

     这也能说明这是变量是靠拷贝构造函数传递的;

    下面来证明两件事

    1:最开始throw异常的的表达式会将异常拷贝到堆里最后由系统回收;

    2:每次拷贝的不是下一层传递来的异常,而是存储在堆中的原始异常;

    先来证明1:

    1. #include
    2. #include
    3. using namespace std;
    4. class m_exception :public exception {
    5. public:
    6. int x = 100;
    7. m_exception(const char* message)
    8. :exception(message){
    9. cout << this << endl;
    10. }
    11. void printAddress() {
    12. cout << this << endl;
    13. }
    14. ~m_exception() {}
    15. };
    16. void f() {
    17. m_exception e= m_exception("e");
    18. throw e;
    19. }
    20. void g() {
    21. try {
    22. f();
    23. }
    24. catch (m_exception e) {
    25. e.x = 1000;
    26. cout << e.x << endl;
    27. e.printAddress();
    28. throw;
    29. }
    30. }
    31. int main() {
    32. try {
    33. g();
    34. }
    35. catch (m_exception e) {
    36. cout << e.x << endl;
    37. e.printAddress();
    38. }
    39. }

    运行结果:

    可以看到,虽然我们在g中修改了x,但是并没有影响到main中的异常,所以上一级的环境并不是拷贝下一级环境的异常;

    当我们将catch的参数改为引用时:

    1. void g() {
    2. try {
    3. f();
    4. }
    5. catch (m_exception& e) {
    6. e.x = 1000;
    7. cout << e.x << endl;
    8. e.printAddress();
    9. throw;
    10. }
    11. }
    12. int main() {
    13. try {
    14. g();
    15. }
    16. catch (m_exception& e) {
    17. cout << e.x << endl;
    18. e.printAddress();
    19. }
    20. }

    运行结果:

    可以看到,两个异常的地址相同,且g中的修改能影响到main;

    综上所述,我们完全有理由肯定,每一层的catch语句都是捕获属于其本身的原异常的拷贝副本;

    我们知道,c++的存储空间可以分为栈空间和堆空间,当我们的能在不同函数之间安全传递的变量只能是堆空间上的变量,所以我们也有充分的理由信息,这个变量是在堆上的;

    证明完毕;

  • 相关阅读:
    C语言数据结构串【BF\KMP算法】
    Clean My Mac X破解版,让您的电脑跟新的一样好用
    C语言中文网 - Shell脚本 - 0
    vue.extend 实现表格,同时编辑多条数据
    通讯网关软件023——利用CommGate X2HTTP实现HTTP访问Modbus TCP
    JavaScript 模块导出示例
    五、DRF 模型序列化器ModelSerializer
    CUDA~矩阵乘运算
    JAVA:实现将位置 i 处的字符与位置 j 处的字符交换的函数算法(附完整源码)
    Leetcode1455 检查单词是否为句中其他单词的前缀
  • 原文地址:https://blog.csdn.net/weixin_62953519/article/details/127918988