当前位置:首页 » 《我的小黑屋》 » 正文

C++的 try-catch 结构

29 人参与  2024年10月26日 16:01  分类 : 《我的小黑屋》  评论

点击全文阅读


文章目录

基本结构关键要点:示例讲解1. 基本异常处理2. 捕获不同类型的异常3. 捕获所有类型的异常4. 自定义异常类程序执行流程: 5. 抛出和重新抛出异常 例外情况:异常规范(Deprecated)异常处理的注意事项总结

C++中的try-catch结构用于异常处理。通过异常处理机制,程序可以在运行过程中捕获和处理错误,而不至于直接导致程序崩溃。try语句块用于标记可能抛出异常的代码,catch语句块用于捕获并处理这些异常。

基本结构

try {    // 可能抛出异常的代码} catch (type1 e1) {    // 处理type1类型异常的代码} catch (type2 e2) {    // 处理type2类型异常的代码} catch (...) {    // 处理所有类型异常的代码(可选的,使用"..."表示捕获任意类型异常)}

关键要点:

try 块:包含可能抛出异常的代码。当遇到异常时,程序会跳出try块,进入与异常类型匹配的catch块。catch 块:用于捕获在try块中抛出的异常,执行相应的处理代码。每个catch块处理一种类型的异常。throw 语句:用来抛出异常,通知调用者发生了某种错误或特殊情况。…(省略号):可以用在最后一个catch块,用来捕获任何类型的异常。

示例讲解

1. 基本异常处理
#include <iostream>int main() {    try {        int a = 10;        int b = 0;                if (b == 0) {            throw "Division by zero error!"; // 抛出异常        }                std::cout << "Result: " << a / b << std::endl;    } catch (const char* e) {  // 捕获异常        std::cerr << "Caught an exception: " << e << std::endl;    }    return 0;}

输出:

Caught an exception: Division by zero error!

在这个例子中,程序试图进行除法运算,但因为除数b为零,所以通过throw语句抛出了一个异常字符串。在catch块中,异常被捕获并输出错误信息。

2. 捕获不同类型的异常

异常可以是任意类型的对象,如整数、字符串、类对象等。可以为不同类型的异常定义多个catch块:

#include <iostream>int main() {    try {        int choice = 1;        if (choice == 1) {            throw 100;  // 抛出整数类型异常        } else if (choice == 2) {            throw "String exception";  // 抛出字符串类型异常        }    } catch (int e) {        std::cerr << "Caught an integer exception: " << e << std::endl;    } catch (const char* e) {        std::cerr << "Caught a string exception: " << e << std::endl;    }    return 0;}

输出:

Caught an integer exception: 100

在这个例子中,choice1,因此抛出了一个整数类型的异常,被第一个catch块捕获。如果抛出的是字符串异常,则会进入第二个catch块。

3. 捕获所有类型的异常

有时候我们不关心具体的异常类型,只想捕获所有异常。可以使用...(省略号)来捕获所有未明确匹配的异常:

#include <iostream>int main() {    try {        throw 3.14;  // 抛出double类型异常    } catch (...) {        std::cerr << "Caught an unknown exception!" << std::endl;    }    return 0;}

输出:

Caught an unknown exception!

这里,catch(...)捕获了double类型的异常,尽管没有具体的catch块来处理double,但省略号可以捕获任何类型的异常。

4. 自定义异常类

通常情况下,C++异常处理不仅限于内置数据类型,还可以通过自定义异常类来传递更加详细的错误信息。我们可以定义自己的异常类,并通过throw语句抛出它:

#include <iostream>#include <string>// 自定义异常类class MyException {public:    MyException(const std::string& message) : msg_(message) {}    const char* what() const noexcept { return msg_.c_str(); }private:    std::string msg_;};int main() {    try {        throw MyException("Something went wrong!");  // 抛出自定义异常    } catch (const MyException& e) {        std::cerr << "Caught MyException: " << e.what() << std::endl;    }    return 0;}

【代码详解】
以下是逐行讲解和注释:

#include <iostream>  // 引入标准输入输出流库,用于输入输出操作#include <string>    // 引入字符串库,用于处理 std::string 类型

这两行头文件引入了标准库中的iostreamstringiostream用于输入输出操作,string用于字符串操作。

// 自定义异常类class MyException {public:    // 构造函数,接收一个字符串参数并将其存储在私有成员变量中    MyException(const std::string& message) : msg_(message) {}    // what()函数,返回异常信息的C风格字符串(const char*),并使用noexcept确保该函数不会抛出异常    const char* what() const noexcept { return msg_.c_str(); }private:    std::string msg_;  // 用于存储异常消息的私有成员变量};
自定义异常类:创建了一个名为MyException的类,它代表一个自定义的异常类。异常类可以存储异常信息,并提供一个方法返回异常信息。构造函数MyException(const std::string& message)是构造函数,它接受一个std::string类型的异常信息,并将其存储在类的私有成员变量msg_中。what()方法what()方法返回一个const char*(C风格的字符串),用于返回异常信息。该方法标记为noexcept,表示它不会抛出异常。私有成员变量msg_:用于存储传入的异常消息。
int main() {

主函数的入口点,程序从这里开始执行。

    try {        // 抛出自定义异常,包含消息 "Something went wrong!"        throw MyException("Something went wrong!");      } 
try 块:尝试执行可能抛出异常的代码。如果发生异常,程序会跳到对应的catch块。throw:抛出一个MyException类型的异常对象,异常消息为 "Something went wrong!"。这会立即跳出try块,进入catch块。
    catch (const MyException& e) {        // 捕获 MyException 类型的异常,并输出异常信息        std::cerr << "Caught MyException: " << e.what() << std::endl;    }
catch 块:当抛出MyException类型的异常时,异常会被捕获在catch块中。捕获的是const MyException&,通过引用避免拷贝,同时使用const保护数据不被修改。输出异常信息e.what()调用的是自定义异常类中的what()方法,用于获取异常信息。std::cerr用于向标准错误流输出捕获的异常消息。
    return 0;  // 返回0表示程序正常结束}

程序正常执行完毕后返回0

程序执行流程:
try块中的代码试图抛出一个MyException异常。异常被throw语句抛出,并被catch捕获。catch块输出异常信息,程序继续执行并最终正常退出。

输出:

Caught MyException: Something went wrong!

在这个例子中,我们定义了一个简单的异常类MyException,并在try块中抛出该类型的异常。在catch块中,捕获并输出了该异常的错误信息。

5. 抛出和重新抛出异常

在某些情况下,捕获异常后可能希望将异常继续向上抛出。可以使用throw重新抛出当前捕获的异常。

#include <iostream>void test() {    try {        throw 20;  // 抛出异常    } catch (int e) {        std::cout << "Caught in test: " << e << std::endl;        throw;  // 重新抛出异常    }}int main() {    try {        test();    } catch (int e) {        std::cout << "Caught in main: " << e << std::endl;    }    return 0;}

输出:

Caught in test: 20Caught in main: 20

在这个例子中,test()函数捕获了异常后,使用throw语句将其重新抛出。然后在main()函数中,重新捕获了该异常并处理。

例外情况:异常规范(Deprecated)

在C++98中,函数可以指定它们会抛出哪些异常类型。但自C++11以来,异常规范已被弃用,并引入了新的noexcept关键字,表示函数不会抛出异常。

void foo() noexcept {    // 这个函数保证不会抛出任何异常}

如果在noexcept函数中抛出异常,程序将调用std::terminate直接终止。

异常处理的注意事项

不要滥用异常:异常处理应该用于无法通过常规手段预测和处理的异常情况。不要使用异常处理来控制正常的程序流,这会降低代码效率并导致混乱。

性能问题:异常的抛出和捕获是有开销的,尤其是在嵌套的try-catch结构中。因此,在高性能代码中,尽量避免在频繁的操作中使用异常处理。

捕获异常时使用引用:如果捕获的是类类型异常,最好使用引用(如const MyException& e)来避免不必要的对象拷贝。

资源释放与异常安全:在处理异常时,特别要注意确保资源(如内存、文件句柄等)能够正确释放,通常通过RAII(资源获取即初始化)模式来保障这一点。

总结

C++中的try-catch结构提供了一种优雅的错误处理机制,允许程序在运行时动态应对异常情况而不至于崩溃。通过自定义异常类、捕获不同类型的异常、甚至捕获所有异常,开发者可以为程序提供更健壮的错误处理。


点击全文阅读


本文链接:http://zhangshiyu.com/post/178107.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1