iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++无try-catch的异常捕获示例详解
  • 538
分享到

C++无try-catch的异常捕获示例详解

C++无try-catch异常捕获C++异常捕获 2022-12-08 20:12:56 538人浏览 泡泡鱼
摘要

目录try-catch没有try-catch的日子Goto 是什么?不同函数之间跳转setjmp 和 longjmpsetjmplongjmp例子无try-catch的异常捕获try

try-catch

c++中,我们可以非常方便的使用try catch来捕获异常

try {
  throw 1;
} catch (int x) {
  cout << "x " << x << endl;
  throw std::runtime_error("exception");
} catch (...) {
  cout << "exception" << endl;
}

你可能有时候 c++的try-catch没什么用

但事实上,在解决某些问题方面,c++的异常强过你自己打flag 判断 比如下面这个例子

void dep2() {
  cout << "ok" << endl;
  throw "error";
}
void dep1() {
  dep2();
  cout << "ok call dep2" << endl;
}
void func() {
  dep1();
  cout << "ok call dep1" << endl;
}
signed main() {
  try {
    func();
  } catch (...) {
    cout << "error" << endl;
  }
  return 0;
}

不使用try-catch 可以怎么写?

pair<int, string> dep2() {
  cout << "ok" << endl;
  return {-1, "error"};
  cout << "ret" << endl;
  return {0, ""};
}
pair<int, string> dep1() {
  auto[ret, err] = dep2();
  if (ret == -1) return {ret, err};
  cout << "ok call dep2" << endl;
  return {0, ""};
}
pair<int, string> func() {
  auto[ret, err] = dep1();
  if (ret == -1) return {ret, err};
  cout << "ok call dep1" << endl;
  return {0, ""};
}
signed main() {
  auto[ret, err] = func();
  if (ret == -1) cout << err << endl;
  return 0;
}

可以看出, try-catch还是可以帮助我们减少一些没必要的判段和代码

没有try-catch的日子

上述是c++的。那么。。。C语言怎么办呢? 那么,大抵是这样的 用返回值来充当状态码返回,传参留一个空位接受返回数据。


int func(int parameter, int* ret) {}

goto 是什么?

goto 语句允许把控制无条件转移到同一函数内的被标记的语句在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。E.W.Dijikstra 在1965年提出结构化程序设计来规避这种错误

goto 就没有他的优点的吗?

goto是个好东西,就是得小心用。

现在的建议是不使用goto,且把goto妖魔化了

确实可以使用 while for之类的东西来替代goto

但是在有些时候,goto还是有一丢丢作用的。

例如:

signed main() {
  for (int i = 1; i <= 1000; i++) {
    for (int j = 1; j <= 1000; j++) {
      for (int k = 1; k <= 1000; k++) {
        if (i == 11 && j == 22 && k == 555)
          goto end;
      }
    }
  }
  end:
  return 0;
}
signed main() {
  bool flag = true;
  for (int i = 1; i <= 1000 && flag; i++) {
    for (int j = 1; j <= 1000 && flag; j++) {
      for (int k = 1; k <= 1000 && flag; k++) {
        if (i == 11 && j == 22 && k == 555)
          flag = false;
      }
    }
  }
  return 0;
}

抛开程序本身不谈,有时候使用goto跳出多级循环的便利性,更胜一筹。

不同函数之间跳转

上述讲的goto只能在同一个函数内进行跳转,不能够跨函数跳转

setjmp 和 longjmp

setjmp

setjmp()函数保存关于调用环境的各种信息(通常是堆栈指针、 缓冲区env中的指令指针,可能是其他寄存器的值和信号掩码) 稍后由longjmp()使用。调用时,setjmp()返回0。(用man setjmp查看更详细的介绍)

创建本地的jmp_buf缓冲区并且初始化,用于将来跳转回此处。这个子程序保存程序的调用环境于env参数所指的缓冲区,env将被longjmp使用。如果是从setjmp直接调用返回,setjmp返回值为0。如果是从longjmp恢复的程序调用环境返回,setjmp返回非零值。

longjmp

在执行longjmp之时,传入一个保存好的jmp_buf和一个返回值,程序就会切换上下文跨函数的跳转到 之前设置的setjump处执行。

例子

jmp_buf env;
signed main() {
  int stat = 0;
  if ((stat = setjmp(env)) == 1) {
    printf("1");
    return 1;
  }
  printf("0");
  longjmp(env, 1);
  return 0;
}
// 结果:
>. 01

原理,进程是一个状态机,我们当前的执行时刻拥有的状态有 寄存器的值,pc指针,堆栈信息等。 和上下文切换一样,我们可以保存一下当前进程的信息在jmp_buf里面,然后,等longjmp调用时,再去以保存的时候的进程信息去“切换”掉当前的状态信息,实现了跳转执行的过程,由于这个和上下文切换还是有区别,是切换回去当前进程。所以保存一下必要的寄存器值就可以了。

无try-catch的异常捕获

利用宏替换和switch来匹配错误

可以简单的实现异常的捕获和跳转

(还是c++的try-catch更强大)

#include <bits/stdc++.h>
#include <setjmp.h>
struct EXP {
  jmp_buf buf;
  int stat;
};
#define BEGIN_EXP(exp) switch (setjmp(exp.buf))
#define TRY(body) case 0: body break;
#define CATCH(exp, body) case exp: body break;
#define THROW(exp, data) longjmp(exp.buf, data)
int main() {
  EXP exp;
  BEGIN_EXP(exp) {
    TRY({
      std::cout << " data" << std::endl;
      THROW(exp, 1);
    })
    CATCH(1, {
      std::cout << "error 1" << std::endl;
      THROW(exp, 2);
    })
    CATCH(2, {
      std::cout << "error 2" << std::endl;
      THROW(exp, 3);
    })
    CATCH(3, {
      std::cout << "error 2" << std::endl;
    })
  }
  return 0;
}

以上就是C++无try-catch的异常捕获示例详解的详细内容,更多关于C++无try-catch异常捕获的资料请关注编程网其它相关文章!

--结束END--

本文标题: C++无try-catch的异常捕获示例详解

本文链接: https://www.lsjlt.com/news/174487.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c语言怎么计算字符串长度
    在C语言中,可以使用内置的strlen()函数来计算字符串的长度。该函数位于string.h头文件中。以下是一个示例代码: #inc...
    99+
    2024-05-14
    c语言
  • c语言怎么判断三个数的大小
    可以通过比较三个数之间的大小关系来判断它们的大小。以下是一个示例代码: #include <stdio.h> int ...
    99+
    2024-05-14
    c语言
  • c++排序函数sort怎么使用
    在C++中,使用sort函数对容器中的元素进行排序,可以按照默认的升序排列,也可以自定义排序规则。 下面是一个简单的例子,对一个ve...
    99+
    2024-05-14
    c++
  • c++中string的compare函数怎么使用
    在C++中,可以使用string的compare函数来比较两个string对象的大小。该函数的原型如下: int compare(c...
    99+
    2024-05-14
    c++
  • c++中string的compare函数有什么用
    c++中string的compare函数用于比较两个字符串的大小关系。该函数返回一个整数值,表示两个字符串的比较结果。 具体来说,如...
    99+
    2024-05-14
    c++
  • c++中print函数的功能有哪些
    在C++中,通常使用std::cout来进行输出操作,而不是使用print函数。std::cout是C++标准库中的一个输出流对象,...
    99+
    2024-05-14
    c++
  • c语言数据结构怎么使用
    在C语言中,数据结构可以通过定义结构体来实现。以下是一些常见的数据结构的使用方法示例: 链表: #include <std...
    99+
    2024-05-14
    c语言
  • c++中print函数的用法是什么
    在C++中没有内置的print函数,但可以使用cout来输出内容到控制台。cout是C++标准库中的一个输出流对象,可以使用<...
    99+
    2024-05-14
    c++
  • c++中concept的用法是什么
    在C++20中,Concept是一种新的语言特性,用于定义类型要求和约束。Concept可以被用来约束函数模板、类模板和普通函数的参...
    99+
    2024-05-14
    c++
  • c++中concept的作用是什么
    在C++中,concept的作用是定义一种通用的约束,用于限制模板参数的类型范围。通过使用concept,可以在编译时对模板参数进行...
    99+
    2024-05-14
    c++
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作