当前位置: 首页 > news >正文

郑州网站建设公司排行北京网站开发品牌

郑州网站建设公司排行,北京网站开发品牌,在线logo免费设计生成器标智客,wordpress 旧版本下载C 基础知识 八 异常处理 上篇 一、基础1. 异常的概念2. 异常的分类2.1 内置异常2.2 自定义异常 3. 异常的处理方式3.1 try-catch 语句3.2 throw 语句3.3 noexcept 修饰符3.4 finally 语句块 二、 异常处理机制1 try-catch 语句块2 异常处理流程3 标准异常类 三、 抛出异常1 thr… C 基础知识 八 异常处理 上篇 一、基础1. 异常的概念2. 异常的分类2.1 内置异常2.2 自定义异常 3. 异常的处理方式3.1 try-catch 语句3.2 throw 语句3.3 noexcept 修饰符3.4 finally 语句块 二、 异常处理机制1 try-catch 语句块2 异常处理流程3 标准异常类 三、 抛出异常1 throw语句2 异常类型3 异常传递 四、 捕获异常1 catch语句2 多个catch语句的顺序与匹配规则3 异常处理机制的使用示例 五、 C11 新增异常功能1 noexcept操作符2 异常列表function try-block) 六、常见错误和异常处理1 空指针异常2 内存泄漏异常3 数组越界异常4 死锁异常 一、基础 1. 异常的概念 异常是程序在运行过程中出现非正常情况的处理机制。当出现异常时程序会停止运行并调用异常处理程序。 2. 异常的分类 异常可以分为内置异常和自定义异常 2.1 内置异常 C 标准库提供了许多预定义的异常类称为内置异常包括以下几种 std::exception所有标准异常类的基类。std::logic_error表示程序逻辑错误。std::runtime_error表示运行时错误。 2.2 自定义异常 除了使用内置异常我们还可以创建自定义异常类来处理特定错误。自定义异常类可以继承自内置异常类以实现异常的精细控制。 3. 异常的处理方式 C 提供了以下几种处理异常的方式 3.1 try-catch 语句 try {// 可能会抛出异常的代码块 } catch (exception1_type exception1_var) {// 处理异常类型1 } catch (exception2_type exception2_var) {// 处理异常类型2 }使用 try 代码块来包含可能抛出异常的代码紧跟 catch 块来处理捕获到的异常。当抛出异常后程序会自动匹配 catch 块中与对应异常相同类型的代码块执行保证程序正常执行。 3.2 throw 语句 throw exception_object;使用 throw 语句抛出一个异常对象使程序进入异常处理模式。 exception_object 可以是基本类型或对象甚至可以是自定义类型的实例。 3.3 noexcept 修饰符 void function_name() noexcept {// 不会抛出异常的函数 }noexcept 修饰符指示函数不抛出异常。使用 noexcept 可以优化程序性能。当程序遇到一个没有 noexcept 修饰符的函数会假设这个函数可能抛出异常导致额外的代码执行。 3.4 finally 语句块 try{// 可能抛出异常的代码块 } catch(...) {// 处理异常 } finally {// 无论有无异常都执行 }finally 语句在 try-catch 语句的末尾执行无论异常是否抛出。通常用于释放资源等程序收尾工作。 综上所述异常处理是程序设计中重要而必不可少的一部分。了解常见的异常处理方式可以让我们更加高效地处理程序中的错误并确保程序的正常运行。 二、 异常处理机制 C中的异常处理机制用于处理程序运行过程中的异常情况。异常可以是程序中的一种错误或者突发事件可能会导致程序崩溃但是正常情况下我们希望程序可以平稳地运行下去去处理这些异常情况。在这样的情况下 C的异常处理机制发挥了巨大的作用。 1 try-catch 语句块 try-catch 是处理 C 异常的关键工具。它的主要作用是将异常处理分离出代码将异常在运行时捕获并处理。 try {// 可能引发异常的代码块 } catch (Type1 arg1) {// 处理Type1类型的异常 } catch (Type2 arg2) {// 处理Type2类型的异常 } catch (Type3 arg3) {// 处理Type3类型的异常 }当一个异常被抛出的时候通常是使用 throw 语句与抛出异常的类型相匹配的 catch 块会被调用它会处理异常并从这个异常中恢复程序执行。 2 异常处理流程 异常处理的整个过程是一种顺序执行模型以下是它的基本流程 程序执行到可能抛出异常的代码时这段代码必须嵌入到 try 块中。如果在 try 块中的代码引发了异常程序会跳转到与抛出异常类型匹配的 catch 块中catch 块负责处理异常。最后程序会从 catch 块中退出向下执行任何后续代码。 简单来说我们可以将异常处理机制的处理过程看作是程序运行时一条流程线它沿着 try-catch 块执行遇到异常时跳转 catch 块那里处理异常最后退出 catch 块。 3 标准异常类 C 标准库中定义了一些异常类这些异常类是所有 C 应用程序都可以使用的。由于这些异常类是预定义的因此它们都是放在 std 命名空间之下。 C 标准库提供的异常类 std::exception —— 所有标准异常类的基类。std::bad_alloc —— 在申请内存失败时抛出。std::bad_cast —— 将一个指向派生类的基类指针强制转换为派生类指针时如果类不是目标类型则抛出。std::ios_base::failure —— I/O 操作失败时抛出。std::out_of_range —— 数组访问越界时抛出。std::invalid_argument —— 提供无效参数时抛出。std::length_error —— 尝试创建一个超出可分配内存大小的vector、string等时发生。std::logic_error —— 人为 bug如出现未在程序中考虑到的条件等通常还有一些 derived class 总结不同的情况此类异常可以在编译环境中静态检查出来。std::runtime_error —— 运行时错误一般情况下是在单个文件运行时出错。常常由文件、网络等外部原因引起 以上这些异常类是为了解决常见的情况而设计的它们能够支持很多常见的内部错误如果我们想要精细控制异常我们还可以创建自定义异常。 通过使用异常处理机制程序员可以保证程序的正常运行在发生异常时捕获并处理它们从而防止程序崩溃。同时使用标准异常类也可以避免一些常见的错误和异常。 三、 抛出异常 在C中可以使用异常处理机制来处理程序中的异常情况。当程序出现错误或突发事件时异常处理机制可以让程序正常运行下去而不会导致程序崩溃。那么如何抛出异常呢我们一起来看看 1 throw语句 使用throw语句可以抛出异常throw语句必须跟上一个表达式该表达式是抛出的异常对象如下所示 throw someException; // 抛出异常我们可以用任何类型的值做为异常对象不过通常我们会把异常对象设置为标准库的异常类之一 2 异常类型 异常类型是某种类型的值它可以用于标识需要通知程序时发生了什么错误。异常类型可以是任意类型但为了能够与 catch 块中的异常参数类型匹配通常使用异常类的对象或指针。 下面是一个简单的示例在函数中抛出一个异常 // 声明一个自定义的异常类 class MyException : public exception { public:// 重写 what() 函数返回异常信息const char* what() const noexcept override {return MyException occurred;} };void myFunction() {throw MyException(); // 抛出自定义异常 }在抛出异常时可以使用任何类型的值但是为了能够被 catch 块所匹配一般使用异常类的对象或指针也可以自定义异常类 3 异常传递 如果在函数中抛出了异常那么异常会被抛到调用该函数的代码中。如果这个函数也没有捕获这个异常那么异常就会继续传递到更高的层次直到被捕获为止。 下面是一个示例代码展示了异常是如何传递的 void functionC() {cout Starting function C endl;throw MyException(); // 抛出自定义异常cout Ending function C endl; }void functionB() {cout Starting function B endl;functionC(); // 调用functionCcout Ending function B endl; }void functionA() {cout Starting function A endl;try {functionB(); // 调用functionB} catch (const exception e) {cerr e.what() endl; // 捕获并处理异常}cout Ending function A endl; }int main() {cout Starting main function endl;functionA(); // 调用functionAcout Ending main function endl;return 0; }输出结果为 Starting main function Starting function A Starting function B Starting function C MyException occurred Ending function A Ending main function首先main函数调用 functionA。functionA 内部调用 functionB并且包含一个 try 块用来捕获异常。functionB 内部调用 functionC并抛出了一个异常这个异常传递到了 functionA 中被 catch 块捕获并处理。 这里需要注意的是一旦抛出了一个异常函数就会终止。因此functionC 中的 cout 语句不会被执行到。 总结起来异常处理机制是 C 中重要的一部分它可以帮助程序处理错误和突发事件并保证程序的正常运行。在抛出异常时需要考虑使用什么类型的异常对象并养成良好的习惯在适当的地方捕获异常。 四、 捕获异常 在C中捕获异常是指捕获并处理由 throw 语句抛出的异常。在异常处理机制中try 块用于捕获异常并处理它们而 catch 块则用于处理 try 块中抛出的异常。下面我们来看看如何使用 catch 块来捕获和处理异常 1 catch语句 catch 块用于捕获和处理由 try 块抛出的异常。catch 块必须跟上一个括号括号中是一个参数它是 catch 块的异常参数用来接收抛出的异常对象 如下所示 try {// 可能会发生异常的代码 } catch (exceptionType e) {// 处理异常的代码 }这里的 exceptionType 是异常类型的名字使用与 throw 语句中抛出的一致的类型或基类类型。e 表示将异常对象的引用传递给 catch 块中的代码从而使得 catch 块能够访问并处理该异常对象。需要注意的是e 表示对异常对象的只读访问不能对传递过来的异常对象进行修改。 我们可以使用多个 catch 块来处理不同类型的异常这样可以将异常处理代码与常规代码分离更好地管理程序错误和异常。下面我们来看看多个 catch 块的顺序和匹配规则 2 多个catch语句的顺序与匹配规则 当由 try 块抛出一个异常时程序会按照由上到下的顺序遍历 catch 块直到找到一个与抛出的异常匹配的 catch 块为止。这里的匹配指的是异常参数类型与抛出的异常对象类型一致或者是该异常的基类类型。如果找不到合适的 catch 块则程序将异常传递到更高层次的代码中。 需要注意的是如果有多个 catch 块可以匹配抛出的异常C 编译器将使用第一个合适的 catch 块进行处理而不是使用最具体的 catch 块。因此在编写多个 catch 块时应该将最具体的 catch 块放在最前面 下面是一个示例它展示了多个 catch 块的顺序和匹配规则 try {// 可能会发生异常的代码 } catch (const Exception1 e) {// 处理异常1的代码 } catch (const Exception2 e) {// 处理异常2的代码 } catch (const Exception3 e) {// 处理异常3的代码 } catch (const exception e) {// 处理其他异常的代码 }在这个示例中当由 try 块抛出 Exception1 类型的异常时程序会执行第一个 catch 块。当抛出 Exception2 类型的异常时程序会执行第二个 catch 块。当抛出 Exception3 类型的异常时程序会执行第三个 catch 块。当抛出其他异常时程序会执行最后一个 catch 块。 3 异常处理机制的使用示例 下面是一个简单的示例它展示了异常处理机制的使用。我们自定义一个异常类 DivideByZeroException用于抛出在除法运算中除数为零的异常。在该程序中我们使用 try 块和 catch 块来捕获和处理异常并且为了更好地管理程序错误和异常将业务逻辑和异常处理代码分离开来。 #include iostream #include exception using namespace std;// 自定义一个异常类 class DivideByZeroException : public exception { public:// 重写 what() 函数返回异常信息const char* what() const noexcept override {return Attempt to divide by zero;} };// 除法函数在该函数中可能会抛出一个 DivideByZeroException 异常 double divide(double a, double b) {if (b 0) {throw DivideByZeroException();}return a / b; }int main() {double a 42, b 0, result;try {result divide(a, b);cout Result is: result endl;} catch (const DivideByZeroException e) {cerr Exception caught: e.what() endl;}cout Program continues to run endl;return 0; }在该示例中定义了一个 除法函数 divide该函数接收两个 double 类型的参数 a 和 b如果除数 b 为零则抛出一个 DivideByZeroException 异常。在程序中我们在 try 块中调用 divide 函数并通过 catch 块来捕获并处理抛出的异常。我们在 catch 块中打印出异常信息并继续执行程序。最后输出的结果应该是 Exception caught: Attempt to divide by zero Program continues to run以上就是关于 catch 块的使用和异常处理机制的一个简单示例希望可以帮助您更好地掌握 C 中的异常处理机制。 五、 C11 新增异常功能 在C11中增加了一些异常的功能让我们来看看 1 noexcept操作符 noexcept是一个C11新增的操作符它用于指明一个函数是否可能抛出异常。当一个函数有可能抛出异常时我们可以在其声明或定义前使用 noexcept 关键字告知编译器这一信息。这个操作符的作用是帮助编译器进行优化提高代码的效率。 一个使用 noexcept 的函数可以被认为是“抛出异常不影响程序正确性”的这意味着该函数不会抛出异常或者抛出异常后程序可以优雅地进行终止。 下面是一个使用 noexcept 关键字的示例 #include iostream using namespace std;void func1() noexcept {cout func1: No exceptions here! endl; }void func2() {throw runtime_error(Exception in func2); }int main() {cout boolalpha;cout func1 is noexcept: noexcept(func1()) endl; // 输出 truecout func2 is noexcept: noexcept(func2()) endl; // 输出 false }在这个示例中定义了两个函数 func1 和 func2其中 func1 使用了 noexcept并且没有抛出任何异常。而 func2 则可能会抛出一个 runtime_error 异常。在主函数中我们使用 noexcept 来检查 func1 和 func2 是否使用了 noexcept 进行声明或定义从而判断它们是否可能会抛出异常。 需要注意的是noexcept 操作符只能用于函数声明或定义的末尾这个末尾必须是分号或花括号。对于类的成员函数可以在函数名后的括号内使用它如下所示 class MyClass { public:void func1() noexcept;void func2() noexcept(true) { // 或者把true换成falsethrow runtime_error(Exception in func2);} };在类的成员函数声明或定义中也可以使用 noexcept 进行限定但有一个细微的差别可以将其放在括号内来表示类作为一个新环境。括号内的布尔值指定了该函数是否可能抛出异常。 2 异常列表function try-block) 在 C11 中还新增了异常列表也叫函数 try 块。这个功能允许我们在函数定义中捕获异常并处理与在函数体中进行异常处理不同这让我们可以将所有异常处理代码放在同一个位置提高代码的可读性和可维护性。 在函数体开始之前在函数参数列表后立即使用 try 关键字并紧跟着花括号在花括号中包含函数体需要同时声明和捕获异常。需要注意的是如果一个函数既有函数 try 块又有普通的 try-catch 块它们的处理顺序是不一样的函数 try 块中的异常处理将先于普通的 try-catch 块执行。 下面是一个函数 try 块的示例代码 #include iostream #include stdexcept using namespace std;class MyClass { public:MyClass() : num(42) {cout Constructing MyClass endl;}~MyClass() noexcept(false) {cout Destructing MyClass endl;throw runtime_error(Exception in destructor);}void DoSomething() noexcept(false) {cout Doing something endl;throw runtime_error(Exception in DoSomething);}private:int num; };void f(MyClass mc) try {mc.DoSomething(); } catch (const exception e) {cerr Caught exception in f(): e.what() endl; }int main() {MyClass mc;f(mc);return 0; }在这个示例中定义了一个 MyClass 类该类包含了一个有副作用的默认构造函数和一个有副作用的析构函数它们都可能会抛出异常。MyClass 类还包含一个成员函数 DoSomething这个函数也可能会抛出异常。我们使用了函数 try 块来定义了一个函数 f该函数调用了成员函数 DoSomething并在函数名后面使用了 try 来声明和捕获异常。在 catch 块中打印出异常信息。 在主函数中创建了一个 MyClass 对象然后调用函数 f 来演示函数 try 块的使用。 以上就是 C11 中新增的两个异常功能noexcept 操作符和异常列表function try-block。这些新功能使我们可以更好地处理异常写出更健壮、高效的代码。 六、常见错误和异常处理 在编写代码时我们难免会遇到一些错误与异常。这些错误与异常可能会导致我们的程序崩溃或者出现一些意想不到的行为。因此在编写代码的过程中我们应该注意一些常见的错误和异常以便及时解决它们或者避免它们的发生。 1 空指针异常 指针是我们编程过程中经常使用的一个概念空指针异常指当我们使用一个空指针时会出现意想不到的行为或意外的程序崩溃。 下面是一个关于空指针异常的代码示例 int* p nullptr; // 定义一个空指针 int a *p; // 这里会发生空指针异常在代码示例中定义了一个空指针 p然后试图去访问 p 指向的内存空间中的值并将其赋值给变量 a这里就会发生空指针异常。 在C 中我们可以通过以下方式来避免空指针异常的发生 在使用指针之前要进行判断确保指针不为空。在给指针分配内存空间时要使用 new 操作符并进行异常处理。 2 内存泄漏异常 内存泄漏指程序在分配了内存空间后没有合适的方式来释放它。内存泄漏会导致程序内存空间的消耗过大从而影响程序性能。 下面是一个内存泄漏的代码示例 int* p new int; // 分配了一个动态内存空间 p nullptr; // 将指针指向空在代码示例中通过 new 操作符动态地分配了一段内存空间但是在之后将指针置为空时我们并没有使用 delete 来释放所分配的内存空间从而导致了内存泄漏。 在C 中应该避免内存泄漏的发生。一种常见的做法是在分配内存空间时使用智能指针smart pointer它们会在指针不再需要时自动释放所分配的内存空间。 3 数组越界异常 数组越界是指访问数组的时候访问一个超出了数组范围的索引其结果是未定义的行为。访问越界的错误有时可能看起来没有任何影响但是在某些情况下它们可能会对程序的运行时行为产生严重的影响。 下面是一个数组越界的代码示例 int arr[5] {1, 2, 3, 4, 5}; int n 6; int a arr[n]; // 这里会发生数组越界在代码示例中定义了一个长度为 5 的数组 arr然后试图访问数组中不存在的索引 n这里就会发生数组越界异常。 在C 中我们可以通过以下方式来避免数组越界异常的发生 在访问数组元素时要确保访问的索引在有效范围内。在使用数组之前要进行初始化。 4 死锁异常 死锁是指两个或多个进程线程相互等待对方释放共享资源从而导致进程线程阻塞的情况。死锁是多线程编程中比较常见的一个问题一旦发生会导致程序的挂起从而影响程序的性能。 下面是一个死锁的代码示例 #include mutex #include threadvoid func(std::mutex m1, std::mutex m2) {m1.lock();m2.lock(); // 这里会导致死锁// ...m2.unlock();m1.unlock(); }int main() {std::mutex m1, m2;std::thread t1(func, std::ref(m1), std::ref(m2));std::thread t2(func, std::ref(m2), std::ref(m1));t1.join();t2.join();return 0; }在代码示例中定义了两个线程 t1 和 t2它们分别执行函数 func。在函数中我们使用了两个互斥量 m1 和 m2 来保证在访问共享资源前线程的同步但是在执行线程 t1 和 t2 的时候如果它们同时试图获取 m1 和 m2 的互斥锁就会导致死锁异常的发生。 在 C 中可以通过以下方式来避免死锁异常的发生 避免使用多个互斥量进行同步。在使用互斥量时谨慎使用 lock 和 unlock使用 RAII 实现自动加锁和解锁在 C11 中我们可以使用 std::lock_guard 和 std::unique_lock 来实现在构造函数中加锁在析构函数中解锁的操作
http://www.sczhlp.com/news/154523/

相关文章:

  • 专业建站推荐玩客云做网站
  • 企业营销类专业网站广州番禺人才网官网
  • 四川省建设工程造价信息网站网站建设 浏览器兼容
  • 题解:P9868 [NOIP2023] 词典
  • 304、渭城曲
  • AtCoder Beginner Contest 425
  • AT_agc052_b [AGC052B] Tree Edges XOR
  • 菠菜网站怎样做安全教育主管部门建设的专题资源网站是
  • 男人和女人做性的网站长沙网站定制
  • 海南住房与城乡建设部网站网站策划用培训吗
  • 网站建设基本要素品牌型网站建设方案
  • 嘉兴网站广优化公司做化验的网站
  • 芍药居做网站公司品牌建设的核心
  • 网站被采集 更换模板电力建设网站进不去
  • 网站建设费会计处理柳州网站建设柳州
  • 株洲网站制作建设青海移动网站建设
  • 域名注册网站搭建wordpress go 跳转
  • 建筑业服务平台手机优化是什么意思
  • 南宁专业做网站方案网站开发的在线支付功能
  • 网站建设丨找王科杰效果好网站防盗链设置
  • 联享品牌网站建设免费主题大全下载
  • 做医院门户网站 上海贵州网站备案
  • 本溪做网站的公司北京欢迎您网站建设
  • 建网站价格网wordpress手机单页面模板
  • 网站开发维护公司经营范围石家庄建设银行河北分行招聘网站
  • 企业网站建设 安全企业网站建设的定位
  • 网站制作的收费电气行业网站建设多少钱
  • 专业网站制作公司招聘自动添加标签wordpress
  • 大家做公司网站 都是在哪里做的国内做外单的网站有哪些
  • 背单词 纯英文 2025年10月