跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C++ 异常安全
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
Admin
(
留言
|
贡献
)
2025年4月28日 (一) 21:26的版本
(Page creation by admin bot)
(差异) ←上一版本 |
已核准修订
(
差异
) |
最后版本
(
差异
) |
下一版本→
(
差异
)
警告:您正在编辑该页面的旧版本。
如果您发布该更改,该版本后的所有更改都会丢失。
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= C++异常安全 = '''异常安全'''(Exception Safety)是C++编程中一个关键概念,指程序在抛出异常时仍能保持正确状态,不泄露资源,不破坏数据一致性。异常安全是编写健壮代码的重要原则,尤其在资源管理、并发编程和复杂系统中至关重要。 == 异常安全的基本保证 == C++中的异常安全通常分为三个级别,按强度从低到高排列: === 1. 基本保证(Basic Guarantee) === * 程序在抛出异常后仍处于有效状态,不会发生资源泄漏或内存损坏。 * 对象仍可被安全销毁,但具体状态可能不确定。 === 2. 强保证(Strong Guarantee) === * 操作要么完全成功,要么失败后程序状态回滚到操作前的状态(类似事务)。 * 通常通过"copy-and-swap"惯用法实现。 === 3. 不抛保证(No-throw Guarantee) === * 操作保证不会抛出任何异常。 * 典型例子:简单getter函数和析构函数(按C++标准,析构函数不应抛出异常)。 <mermaid> pie title 异常安全保证级别 "基本保证" : 40 "强保证" : 35 "不抛保证" : 25 </mermaid> == 代码示例 == === 基本保证示例 === <syntaxhighlight lang="cpp"> #include <iostream> #include <stdexcept> class ResourceHolder { int* resource; public: ResourceHolder() : resource(new int(42)) {} ~ResourceHolder() { delete resource; // 确保资源释放 } void riskyOperation(bool fail) { int* temp = new int(100); // 可能泄漏的资源 if (fail) { delete temp; // 失败时清理 throw std::runtime_error("Operation failed"); } delete resource; // 释放旧资源 resource = temp; // 转移所有权 } }; </syntaxhighlight> '''解释''':即使抛出异常,也没有资源泄漏,满足基本保证。 === 强保证示例(copy-and-swap惯用法) === <syntaxhighlight lang="cpp"> #include <algorithm> #include <stdexcept> class String { char* data; size_t length; void swap(String& other) noexcept { std::swap(data, other.data); std::swap(length, other.length); } public: String& operator=(const String& rhs) { String temp(rhs); // 所有可能抛出异常的操作在这里完成 swap(temp); // 不抛出的交换操作 return *this; // temp离开作用域,清理旧资源 } // ... 其他成员函数 }; </syntaxhighlight> '''解释''':如果拷贝构造失败,原对象不受影响;只有所有操作成功后才会修改状态。 == 异常安全实践 == === RAII(资源获取即初始化) === C++异常安全的核心技术是RAII模式: <syntaxhighlight lang="cpp"> #include <memory> #include <fstream> void processFile(const std::string& filename) { std::ifstream file(filename); // RAII对象,析构时自动关闭文件 if (!file) { throw std::runtime_error("无法打开文件"); } // 使用文件 - 即使这里抛出异常,文件也会正确关闭 // ... } // 文件在这里自动关闭 </syntaxhighlight> === STL中的异常安全 === 标准库容器提供不同级别的保证: * 向量(vector)的<code>push_back</code>:强保证(除非元素拷贝/移动构造函数抛出) * 关联容器的插入操作:通常提供强保证 == 数学表达 == 异常安全可以用事务概念形式化表示。设操作前状态为<math>S_0</math>,操作后状态为<math>S_1</math>: * '''基本保证''': <math>\forall \text{异常} e, \exists S' \text{有效状态}, S' \neq \text{未定义}</math> * '''强保证''': <math>\forall \text{异常} e, \text{状态} = S_0 \text{或操作完全成功}</math> * '''不抛保证''': <math>P(\text{抛出异常}) = 0</math> == 实际案例 == '''数据库事务处理''': <syntaxhighlight lang="cpp"> class DatabaseTransaction { Database& db; public: explicit DatabaseTransaction(Database& db) : db(db) { db.beginTransaction(); } ~DatabaseTransaction() noexcept { if (std::uncaught_exceptions()) { db.rollback(); // 异常发生时回滚 } else { db.commit(); // 否则提交 } } // 禁用拷贝 DatabaseTransaction(const DatabaseTransaction&) = delete; DatabaseTransaction& operator=(const DatabaseTransaction&) = delete; }; void updateAccounts(Account& a, Account& b, int amount) { DatabaseTransaction trans(db); a.withdraw(amount); // 可能抛出 b.deposit(amount); // 可能抛出 // 如果到达这里,事务自动提交 } </syntaxhighlight> '''分析''': 1. 使用RAII管理事务生命周期 2. 析构函数检测是否在异常上下文中 3. 提供强异常保证:要么全部完成,要么全部回滚 == 最佳实践 == * 优先使用RAII管理所有资源(内存、文件句柄、锁等) * 析构函数必须不抛出异常 * 对于可能失败的操作,考虑提供强保证 * 使用<code>noexcept</code>标记不会抛出的函数 * 在修改对象状态前完成所有可能抛出异常的操作 * 使用标准库智能指针(<code>std::unique_ptr</code>, <code>std::shared_ptr</code>)管理动态内存 == 常见陷阱 == 1. '''在构造函数中抛出异常''': - 如果构造函数抛出,析构函数不会被调用 - 需要在抛出前手动清理已分配的资源 2. '''虚函数中的异常规范''': - 派生类重写的虚函数不能添加新的异常类型 3. '''异常与多线程''': - 异常不应跨越线程边界传播 - 使用<code>std::promise</code>/<code>std::future</code>在线程间传递异常 == 总结 == 异常安全是C++健壮编程的核心要求。通过理解三种保证级别并应用RAII等技术,可以构建在异常情况下仍能保持正确性的系统。记住: * 基本保证是底线 * 尽可能提供强保证 * 关键操作(如析构)应提供不抛保证 随着C++标准演进(如C++11引入的<code>noexcept</code>,C++17的<code>std::uncaught_exceptions</code>),编写异常安全代码的工具在不断改进,但基本原则保持不变。 [[Category:编程语言]] [[Category:C++]] [[Category:C++ 异常处理]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)