• C/C++相对论——C++中为什么要使用异常(跳转语句会造成对象没有被析构)


    C++中为什么要使用异常?

    很多人也许知道C++中的异常机制,很多人也许不知道。很多人知道C中常用的assert,也知道在编译时候指定NODEBUG来忽略它。

    对于C语言,使用正常的if-else即是很好的选择,而在C++中,如果使用了面向对象的编程,最好还是使用Exception机制。这主要设计对象能否正确的析构的问题。

    C中的出错跳转setjmplongjmp

    C语言中常用的用于处理异常的方法。它不像abort或者assert或者exit那样直接退出,也不像goto语句仅仅局限在函数内部。
    它是用于一种长跳转的方式。可以从一个函数跳到这个函数上层的调用函数中。
    举个例子

    1. 函数 A 中调用了setjmp设置了一个跳转位,然后函数A调用了函数B。
    2. 函数 B 中调用了longjmp,那么会使得程序条到 函数 A中调用setjmp的位置继续执行。

    这不是本文的重点。

    使用setjmplongjmp最大的缺点是可能会跳过某些对象的构造或者析构。
    还有,在C中使用goto可以跳过某些变量的定义,但是这不会出什么问题。可以试试下面的代码。注意,是C语言,你要是用C++的编译器来编译,应该是会报错的。

    复制代码
     1 #include <stdio.h>
     2 
     3 int main(int argc,char** argv)
     4 {
     5     if(argc > 1){
     6         goto nodef;
     7     }
     8     int a = 102;
     9 nodef:
    10     printf(" a = %d
    ",a);
    11     return 0;
    12 }
    复制代码

    C++中使用setjmplongjmp造成的不良后果

    我们先看代码

    无法正常析构对象的代码

    复制代码
     1 #include <iostream>
     2 #include <csetjmp>
     3 
     4 using std::cout;
     5 using std::endl;
     6 
     7 class Test{
     8     public:
     9         Test(){ cout<<"Test 构造"<<endl;}
    10         ~Test(){cout<<"Test 析构"<<endl;}
    11 };
    12 
    13 jmp_buf jbuf;   //用于setjmp保存当前相关信息
    14 
    15 void calljmp()
    16 {
    17     Test t; //测试能够正确调用析构
    18     cout<<"call longjmp(jbuf,3721)"<<endl;
    19     longjmp(jbuf,3721);
    20 }
    21 
    22 int main()
    23 {
    24     int ret=0;
    25     if( 0 == (ret=setjmp(jbuf))){
    26         cout<<"call setjmp(jbuf) resuces"<<endl;
    27         calljmp();
    28     }
    29     else{
    30         cout<<"call setjmp(jbuf) failed   ret = "<< ret <<endl;
    31     }
    32 }
    复制代码

    编译执行看看

    可以看到,对象构造了,但是没有正常的调用析构。

    复制代码
    1 o@o-pc:~/code_/exception$ g++ setjmp.cpp -o setjmp
    2 o@o-pc:~/code_/exception$ ./setjmp 
    3 call setjmp(jbuf) resuces
    4 Test 构造
    5 call longjmp(jbuf,3721)
    6 call setjmp(jbuf) failed   ret = 3721
    复制代码

    C++中使用异常处理的情况

    C++中使用异常机制的好处之一,就是能够正确的去析构对象。

    使用了异常处理机制的代码

    复制代码
     1 #include <iostream>
     2 #include <csetjmp>
     3 
     4 using std::cout;
     5 using std::endl;
     6 
     7 class Test{
     8     public:
     9         Test(){ cout<<"Test 构造"<<endl;}
    10         ~Test(){cout<<"Test 析构"<<endl;}
    11 };
    12 
    13 jmp_buf jbuf;   //用于setjmp保存当前相关信息
    14 
    15 void calljmp()
    16 {
    17     Test t; //测试能够正确调用析构
    18     cout<<"call longjmp(jbuf,3721)"<<endl;
    19     //longjmp(jbuf,3721);
    20     throw 3721;
    21 }
    22 
    23 int main()
    24 {
    25     try{
    26         cout<<"调用calljmp 尝试抛出异常"<<endl;
    27         calljmp();
    28     }catch(int t){
    29         cout<<"捕获到异常值:"<<t<<endl;
    30     }
    31     /*
    32     int ret=0;
    33     if( 0 == (ret=setjmp(jbuf))){
    34         cout<<"call setjmp(jbuf) resuces"<<endl;
    35         calljmp();
    36     }
    37     else{
    38         cout<<"call setjmp(jbuf) failed   ret = "<< ret <<endl;
    39     }
    40     */
    41 }
    复制代码

    编译运行试试

    可以看到这次正常调用了析构函数

    复制代码
    o@o-pc:~/code_/exception$ g++ exception.cpp -o exception
    o@o-pc:~/code_/exception$ ./exception
    调用calljmp 尝试抛出异常
    Test 构造
    call longjmp(jbuf,3721)
    Test 析构
    捕获到异常值:3721
    复制代码

    http://www.cnblogs.com/oloroso/p/4616502.html

  • 相关阅读:
    Cpp -- static变量不属于类的实例
    单例模式
    WebView android
    网络编程之一
    初涉json
    初涉XML
    关于JSON的GSON
    网络编程(一)
    硬件51
    重拾C之数据
  • 原文地址:https://www.cnblogs.com/findumars/p/6253626.html
Copyright © 2020-2023  润新知