设为首页 收藏本站
查看: 23|回复: 0

[经验分享] C++ :try 语句块和异常处理

[复制链接]
累计签到:53 天
连续签到:2 天
发表于 5 天前 | 显示全部楼层 |阅读模式
C++ 异常处理机制:try、catch 和 throw
异常处理是 C++ 中处理运行时错误的机制,通过 ​分离正常逻辑与错误处理 提升代码可读性和健壮性。

​1. 基本结构
异常处理由三个关键字组成:

​try:包裹可能抛出异常的代码块。
​catch:捕获并处理特定类型的异常。
​throw:主动抛出异常对象。
[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

try {

    // 可能抛出异常的代码

    if (error_condition) {

        throw exception_object; // 抛出异常

    }

} catch (ExceptionType1 &e) {

    // 处理 ExceptionType1 类型异常

} catch (ExceptionType2 &e) {

    // 处理 ExceptionType2 类型异常

} catch (...) {

    // 捕获所有未处理的异常(不推荐滥用)

}






​2. 异常处理流程
注意:catch(...)捕获所有异常,但无法获取异常信息,通常用于最后兜底。

​抛出异常:当throw执行时,程序立即终止当前代码块,开始查找匹配的catch块。
​栈展开​(Stack Unwinding):
从抛出点开始,逐层退出函数调用栈,直到找到匹配的catch块。
退出时,当前作用域的局部对象会被析构(依赖RAII机制)。
​匹配catch块:
catch块按声明顺序匹配异常类型。
若未找到匹配的catch块,调用std::terminate()终止程序。

​3. 标准异常类
C++ 标准库定义了一组异常类(需包含 <stdexcept>):


示例:使用标准异常

[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

#include <stdexcept>

#include <vector>

  

void checkIndex(const std::vector<int>& vec, int index) {

    if (index < 0 || index >= vec.size()) {

        throw std::out_of_range("索引越界");

    }

}






​4. 自定义异常类
通过继承 std::exception 定义特定错误类型:

[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

#include <exception>

#include <string>

  

class MyException : public std::exception {

public:

    MyException(const std::string& msg) : msg_(msg) {}

    const char* what() const noexcept override {

        return msg_.c_str();

    }

private:

    std::string msg_;

};

  

// 使用自定义异常

throw MyException("自定义错误消息");







[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

noexcept 关键字

​声明函数不抛出异常:

void safe_function() noexcept {

    // 保证不会抛出异常

}






​移动构造函数/析构函数:建议标记为 noexcept,避免容器操作(如 std::vector 扩容)时回退到低效拷贝。
​noexcept 运算符:检查表达式是否可能抛出异常。
[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

bool is_noexcept = noexcept(safe_function()); // true







​5. 捕获异常的最佳实践
​按派生类到基类顺序捕获:确保更具体的异常优先处理。
​通过引用捕获:避免对象切片(尤其对多态异常类)。
​处理已知异常:避免滥用 catch (...)。
​优先使用标准异常类:如std::runtime_error,而非基本类型。
​按顺序捕获异常:先捕获派生类,再捕获基类。
​避免空catch块:至少记录错误信息。
​资源管理用RAII:如std::unique_ptr、std::lock_guard。
​限制异常使用:仅处理严重错误,避免性能损耗。
[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

#include <iostream>

#include <fstream>

#include <stdexcept>

  

class FileReader {

public:

    FileReader(const std::string& filename) : file_(filename) {

        if (!file_.is_open()) {

            throw std::runtime_error("无法打开文件: " + filename);

        }

    }

    // 使用RAII自动关闭文件

    ~FileReader() noexcept = default;

  

    void read() {

        // 读取文件内容(可能抛出异常)

    }

  

private:

    std::ifstream file_;

};

  

int main() {

    try {

        FileReader reader("nonexistent.txt");

        reader.read();

    } catch (const std::runtime_error& e) {

        std::cerr << "错误: " << e.what() << std::endl;

    } catch (...) {

        std::cerr << "未知错误" << std::endl;

    }

    return 0;

}






​6. 重新抛出异常
在 catch 块中可重新抛出当前异常(保留原始异常信息):

[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

catch (const std::exception &e) {

    std::cerr << "记录错误: " << e.what() << std::endl;

    throw; // 重新抛出异常,供上层处理

}






​7. 异常安全(Exception Safety)​
确保代码在异常发生时仍保持数据一致性,分三个等级:

实现强保证的示例:

[C#] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

void updateData() {

    auto backup = data_; // 备份原始数据

    try {

        modifyData();     // 可能抛出异常的操作

    } catch (...) {

        data_ = backup;   // 失败时恢复备份

        throw;

    }

}






​8. 异常处理与资源管理(RAII)​
通过 ​资源获取即初始化(RAII)​ 自动释放资源(如内存、文件句柄),避免异常导致泄漏:

[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

#include <memory>

#include <fstream>

  

void processFile(const std::string& filename) {

    std::ofstream file(filename); // 文件自动管理

    if (!file) {

        throw std::runtime_error("无法打开文件");

    }

    // 使用 file 对象,即使抛出异常也会自动关闭文件

}







​9. 综合示例
[C++] [color=rgb(51, 102, 153) !important]纯文本查看 [color=rgb(51, 102, 153) !important]复制代码
[color=rgb(255, 255, 255) !important]
[color=#ffffff !important]?

运维网代码
01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

#include <iostream>

#include <stdexcept>

  

class NetworkError : public std::runtime_error {

public:

    NetworkError() : std::runtime_error("网络连接失败") {}

};

  

void connectToServer() {

    bool connectionFailed = true;

    if (connectionFailed) {

        throw NetworkError();

    }

}

  

int main() {

    try {

        connectToServer();

    } catch (const NetworkError &e) {

        std::cerr << "错误: " << e.what() << std::endl;

        // 尝试重连或终止程序

    } catch (const std::exception &e) {

        std::cerr << "其他错误: " << e.what() << std::endl;

    }

    return 0;

}






​10. 注意事项
​析构函数中的异常:析构函数默认应为 noexcept,若抛出异常可能导致程序终止。
​性能开销:异常处理比返回错误码略慢,但现代编译器优化后差异较小。
​适用场景:适合处理不可恢复的错误(如文件缺失、内存不足)。

​11. 总结







运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-1005732-1-1.html 上篇帖子: 2025 年,C++ 还能“硬核”多久? 下篇帖子: 没有了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表