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

模板网站zencart公司网址

模板网站zencart,公司网址,免费域名注册2023,网站设计公司网站专业✨个人主页#xff1a; 北 海 #x1f389;所属专栏#xff1a; C修行之路 #x1f383;操作环境#xff1a; Visual Studio 2022 版本 17.6.5 文章目录 #x1f307;前言#x1f3d9;️正文1.异常基本概念1.1.C语言异常处理方式1.2.C异常处理方式 2.异常的使用2.1.异常… ✨个人主页 北 海 所属专栏 C修行之路 操作环境 Visual Studio 2022 版本 17.6.5 文章目录 前言️正文1.异常基本概念1.1.C语言异常处理方式1.2.C异常处理方式 2.异常的使用2.1.异常的抛出与捕获2.2.异常的重新抛出2.3.异常安全2.4.异常规范 3.异常体系3.1.C标准库的异常体系3.2.自定义异常体系 4.异常的优缺点 总结 前言 异常处理在软件开发中扮演着关键的角色它为程序员提供了一种有力的手段来处理和响应程序执行过程中可能出现的错误。本文将深入探讨异常的基本概念、异常处理方式、异常的使用技巧和异常体系的设计以帮助开发者更好地理解和应用异常处理机制 ️正文 1.异常基本概念 1.1.C语言异常处理方式 在 C语言 中面对异常主要有以下两种处理方式 返回错误码终止进程 比如 main 函数有一个返回值只有返回值错误码为 0 时才表示程序正常退出如果发生越界访问、堆栈溢出等行为时会返回其他数值 部分错误码及其对应的错误信息对照表格如下 代码错误信息0成功Success1一般错误General error2误用shell命令Misuse of shell command126无法执行Cannot execute127命令未找到Command not found128无效的退出参数Invalid exit argument130CtrlC终止Terminated by CtrlC255退出状态未知Unknown exit status 至于其他代码的具体含义取决于编译器的不同的实现比如上面的 3 号错误码在 VS 中就表示 异常退出具体原因是 越界访问 除了返回错误码外C语言 还支持通过函数终止进程说白了就是给进程发送 信号 可以使用 exit(err_code)、abord()、assert(bool_exp) 等函数终止进程 exit(err_code) 支持在终止进程时设置错误码可以根据自己的需要建立 [错误码, 错误信息] 的映射关系 abord() 函数则是直接发送 6 号信号来终止进程 至于 assert(bool_exp) 常用于非法情况的检查判断bool_exp 是一个返回类为 bool 的表达式如果该表达式为 假那么 assert 函数就会触发并终止进程 注意 使用 assert 需要包含相关头文件 #include iostream #include cassertusing namespace std;int main() {int x 10;int y 0;// 简易整数除法[]()-void{// 除数分母不能为 0assert(y);cout x / y endl;}();return 0; }assert 最大的优点在于 指明终止原因以及原因出现的具体路径、具体行号对于程序调试十分友好需要 注意 的是 assert 只能在 Debug 模式下使用Release 模式中 assert 会被自动删除 1.2.C异常处理方式 无论是 错误码 还是 终止进程都只能提供简略的错误信息对于 C 这种面向对象的语言来说太无力了需要一种全新的异常处理方式将异常化做一个对象配合异常体系解读异常 万物皆可为对象所以新的异常处理方式非常强大 C 中新增了以下三个关键字用于实现 异常监测、异常抛出、异常捕获 try 监测当前代码区域是否存在异常throw 识别到异常后抛出异常catch 捕获抛出的异常如果有的话 注throw 是一个关键字可以直接在后面跟异常对象也可以像函数调用一样传递异常对象类似于 sizeof 关键字 比如这样就可以使用 C 的异常处理方式 void func() {// 出现异常抛出throw 这是一个异常// 或者// throw(这是一个异常) }int main() {try{// 监测代码当前代码区域func();}catch(const char* ps){// 捕获异常// 可以对 ps 进行操作}return 0; }注意 catch 块捕获的异常对象类型必须与 throw 抛出的异常对象类型匹配上否则会导致异常无法捕获导致程序异常终止 如果正确编写异常处理的代码try 内的代码发生异常时可以优雅处理不至于直接引发进程终止因此 try 内的代码又被称为 保护代码 2.异常的使用 2.1.异常的抛出与捕获 异常的使用比较简单将之前整数相除的代码改成 C 的异常处理方式 void divisor(int x, int y) {if (y 0){// 除 0 错误抛出异常throw(除数分母不能为0);}cout 结果 x / y endl; }int main() {try{divisor(10, 0);}catch (const char* s){cout s endl;}return 0; }通常需要在异常捕获的地方记录日志方便排查错误 如果传入的数据是正确的就不会触发异常程序正常运行 // ...int main() {try{divisor(10, 10);}catch(const char* s){cout s endl;}return 0; }异常在抛出后是必须被捕获的如果不写 catch 块相关代码或者 catch 块中的类型与抛出的异常类型不匹配在出现异常后进程会因异常没有被捕获而被 abort 函数终止 void divisor(int x, int y) {if (y 0){// 除 0 错误抛出异常throw(除数分母不能为0);}cout 结果 x / y endl; }int main() {try{divisor(10, 0);}catch (int s) // 故意写错类型{cout s endl;}return 0; }现在的编译器都很智能如果你在代码编写阶段一个 catch 块都没写会直接报语法错误所以一定要确保抛出的异常能被正确捕获 catch 块至少得存在一个也可以存在多个当同时存在多个 catch 块时抛出的异常会根据栈帧顺序被最近的 catch 块捕获 catch 块只能进入一次异常被捕获后无法再进入其他 catch 块 注意 如果出现多个类型不匹配的 catch 块时异常会被类型匹配且最近的 catch 块捕获 void divisor(int x, int y) {if (y 0){// 除 0 错误抛出异常throw(除数分母不能为0);}cout 结果 x / y endl; }void calc() {int x 10;int y 0;try{divisor(x, y);}catch (const char* s){cout void calc() endl;cout s endl;} }int main() {try{calc();}catch (const char* s){cout int main() endl;cout s endl;}return 0; }当 divisor 函数捕获异常后main 函数中不再捕获异常代码正常运行结束一般异常捕获这个工作会交给最外层统一处理比如这里的 main 函数此时如果出现了异常代码会直接跳转至 main 函数中至于中间的栈帧会被 throw 自动清理 void divisor(int x, int y) {if (y 0){// 除 0 错误抛出异常throw(除数分母不能为0);}cout 结果 x / y endl; }void calc() {int x 10;int y 0;divisor(x, y); }int main() {try{calc();}catch (const char* s){cout int main() endl;cout s endl;}return 0; }在实际使用中并不会这样直接抛出一个字符串而是构建一个 异常信息类抛出一个 异常对象类中包罗万象需要包含最基本的两个信息错误码、错误信息 // 异常信息类 class Exception { public:Exception(int errcode, const string content):_errno(errcode), _content(content){}void what() const{// 打印异常信息cout 发生了异常 endl;cout \t错误码为: _errno endl;cout \t错误信息为: _content endl;} private:int _errno 0;string _content; };这样一来在出现异常时可以构建一个异常对象并抛出 为什么要设计错误码 因为在某些场景中不方便直接暴露错误比如消息发送过程中如果遇到网络问题检测到错误码为 x会不断重试直到发送成功或超时这样能使用户体验更好 throw(Exception(3, 除数分母不能为0));// 现在引用的是临时对象 catch(const Exception e);注意 catch 块捕捉时不可以直接使用左值引用因为抛出的是一个局部对象 当出现未知异常时如何解决 通过 catch(...) 捕获支持捕获任意类型的异常 void calc() {// 故意抛出一个未知异常throw(10); }int main() {try{calc();}catch (const Exception e){cout int main() endl;e.what();}catch (...){cout int main() endl;cout 未知异常 endl;}return 0; }catch(...) 就相当于异常捕获的底线如果前面的 catch 块都无法捕获异常此时就轮到 catch(...) 登场避免程序因异常无法捕获而终止 异常支持使用父类指针/引用捕获子类对象假设当前项目中存在网络异常、数据异常、SQL异常 等多种异常信息类如果想让最外层的 catch 块捕获所有异常对象可以让这些异常信息类都继承自同一个父类同时重写父类中的虚函数再通过父类指针/引用捕获 #include iostream #include string #include windows.husing namespace std;// 父类 class Exception { public:Exception(int errcode, const string content):_errno(errcode), _content(content){}virtual string what() const{return to_string(_errno) : _content;}protected:int _errno 0;string _content; };// 网络子类 class HttpException : public Exception { public:HttpException(int errcode, const string content, const string url, const string type):Exception(errcode, content), _url(url), _type(type){}// 重写virtual string what() const{return to_string(_errno) : _content --- _type _url;}private:string _url; // 资源路径string _type; // 请求类型 };// 内存子类 class CacheException : public Exception { public:CacheException(int errcode, const string content):Exception(errcode, content){}// 重写virtual string what() const{return to_string(_errno) : _content;} };// SQL子类 class SqlException : public Exception { public:SqlException(int errcode, const string content, const string sql):Exception(errcode, content),_sql(sql){}// 重写virtual string what() const{return to_string(_errno) : _content --- _sql;}private:string _sql; // SQL语句 };void SqlServe() {int n rand();if (n % 5 3)throw(SqlException(3, 数据表不存在, select * from t2));else if (n % 5 4)throw(SqlException(4, 权限不足, drop table t1));// 操作完成cout 请求已完成 endl ------------------- endl; }void CacheServe() {int n rand();if (n % 5 2)throw(CacheException(2, 数据不存在));// 进入下一层SqlServe(); }void HttpServe() {int n rand();if (n % 5 0)throw(HttpException(0, 请求的资源不存在, /index.html HTTP/1.1, GET));else if (n % 5 1)throw(HttpException(1, 没有访问权限, /image.html HTTP/1.1, POST));// 进入下一层CacheServe(); }int main() {srand((size_t)time(nullptr));while (true){Sleep(1000);try{cout 开始请求 endl;HttpServe();}catch (const Exception e){// 异常处理cout e.what() endl endl;}catch (...){cout 未知异常 endl;}}return 0; }这里用到了 继承 多态 相关知识当子类对象赋值给父类指针/引用时会触发 切片 机制这个过程是天然发生的所以但凡是从该父类派生出的子类对象都可以被正常接收 这种玩法在实际开发中非常实用项目组可以根据自己的需求设计继承体系以及异常体系 注意 如果同时存在类型为父类及子类的 catch 块异常会被较近的 catch 块捕捉 2.2.异常的重新抛出 异常抛出后可能会导致某些栈帧中的代码没有被执行从而引发内存泄漏等问题比如下面场景中就出现了内存泄露问题 // 异常信息类 class Exception { public:Exception(int errcode, const string content):_errno(errcode), _content(content){}string what() const{return to_string(_errno) : _content;} public:int _errno 0;string _content; };void divisor(int x, int y) {if (y 0){// 除 0 错误抛出异常Exception e(3, 除数分母不能为0);throw(e);}cout 结果 x / y endl; }void calc() {int x 10, y 0;int* arr new int[10];divisor(x, y);delete[] arr;cout delete[] arr: arr endl; }int main() {try{calc();}catch (const Exception e){cout int main() endl;cout e.what() endl;}catch (...){cout int main() endl;cout 未知异常 endl;}return 0; }可以看到动态开辟的空间并没有被正确释放这是因为异常抛出后throw 会清理 calc 的栈帧导致其中的代码没有被执行要想正确的释放内存需要在 calc 函数中主动捕获异常将空间释放后重新抛出异常 注throw 表示捕获到什么异常就抛出什么异常 void calc() {int x 10, y 0;int* arr new int[10];try{divisor(x, y);}catch (...){delete[] arr;cout delete[] arr: arr endl;throw;}delete[] arr;cout delete[] arr: arr endl; }现在空间被释放了同时异常正常交给了最外层处理不过这种写法的代码不容易维护好在 C 中诞生了 智能指针能自动释放空间这也是下一篇博客的内容 为什么异常要在统一的地方进行处理 统一记录日志针对某些错误进行额外处理 2.3.异常安全 异常在使用时需要注意以下几点 1.最好不要在构造函数中抛出异常因为对象的构造和初始化是需要时间的如果在构造途中抛出了异常会导致对象构造不完整 2.最好不要在析构函数中抛出异常析构函数清理资源的过程同样需要时间析构途中抛出异常可能会引发内存泄漏 3.在使用诸如 new/delete、malloc/free、fopen/fclose、lock/unlock 等资源管理配套函数时需要特别注意资源泄漏或者死锁问题在发生捕获到异常后需要先把资源释放了再考虑异常处理 2.4.异常规范 异常就像一只薛定谔的猫你永远不知道别人是否抛出、何时抛出为了让异常的使用更加规范C98 标准规定 可以在函数的后面接 throw(type1, type2, type3 ...)列出这个函数可能抛掷的所有异常类型函数的后面接 throw( )表示该函数不会抛出异常若无异常接口声明则此函数可以抛掷任何类型的异常 比如这样编写函数 void func1() throw(int, char, string); // 可能抛出这三种类型的异常void func2() throw(); // 该函数不会抛出异常void func3(); // 该函数可以抛出任何类型的异常在标准库函数中就采用了这种规范写法 C98 中的异常规范过于繁琐由于异常规范并非强制性语法实际使用过程中有很多人都不会遵守于是在 C11 中对异常规范进行了相关更新化繁为简只需使用一个 noexcept 关键字表明该函数不会抛出异常 void func2() noexcept; // 该函数不会抛出异常推荐使用 C11 中新方案对于不会抛出异常的函数使用 noexcept 关键字修饰 noexcept 可以检测当前函数中是否发生了 throw 抛出异常的行为 如果加了 noexcept 关键字后函数仍然抛出异常是否会报错 答案是会的会直接被 abort 函数终止进程所以可以放心使用 noexcept 关键字即便是在异常抛出与异常捕获的中间函数中使用 noexcept 修饰在异常抛出后进程也会被终止总之就是加了 noexcept 修饰后所有该函数涉及的操作都不会出现异常 注如果使用 throw() 修饰仍然抛出异常后进程不会终止所以还是推荐使用 noexcept 3.异常体系 3.1.C标准库的异常体系 C 标准库中提供了一套 异常体系其中包含了各种常见异常我们也可以继承 std::exception 父类重写其中的虚函数实现其他方面的异常 异常描述std::exception该异常是所有标准C异常的父类std::bad_alloc该异常可以通过new抛出std::bad_cast该异常可以通过dynamic_cast抛出std::bad_typeid该异常可以通过typeid抛出std::bad_exception这在处理C程序中无法预期的异常时非常有用std::logic_error理论上可以通过读取代码来检测到的异常std::runtime_error理论上不可以通过读取代码来检测到的异常std::domain_error当使用了一个无效的数学域时会抛出该异常std::invalid_argument当使用了无效的参数时会抛出该异常std::length_error当创建了太长的std::string时会抛出该异常std::out_of_range该异常可以通过方法抛出例如std::vector和std::bitset::operatorstd::overflow_error当发生数学上溢时会抛出该异常std::range_error当尝试存储超出范围的值时会抛出该异常std::underflow_error当发生数学下溢时会抛出该异常 3.2.自定义异常体系 虽然 C 标准库中提供了标准异常体系但实际上大多数公司会根据实际项目定义自己的异常体系比如之前的 SqlException 等异常信息类就属于自定义异常体系 为什么要自定义异常体系 因为公司中的项目一般都会进行模块划分不同的模块用于实现不同的功能如果不通过自定义异常体系来规范异常行为会导致整个项目的异常处理及其麻烦有了自定义异常体系后只需要通过一个父类指针/引用即可捕获不同子类对象异常统一进行处理 4.异常的优缺点 异常的优点 可以展示更丰富的错误信息更好的定位程序 Bug错误码是层层返回的不方便定位问题而异常是则直接被捕获的很多的第三方库都包含了异常需要与其进行兼容比如 boost、gtest、gmock部分函数使用异常更好表示错误比如 T operator[](size_t pos) 如果越界了就抛异常而不是返回 T() 或 断言 异常的缺点 执行流跨度过大并且非常混乱导致跟踪调试程序时比较困难异常有一些性能上的开销当代硬件速度很快可以忽略不计C 没有垃圾回收机制资源需要自己管理可以使用 RAII 来处理资源管理问题C 标准库的异常体系定义不够好导致出现了各种异常体系比较混乱异常尽量规范使用否则后果不堪设想 抛出异常类型都继承自一个基类函数是否抛异常可以使用 noexcept 注明 总体而言异常 利大于弊在工程项目中鼓励使用异常OO 语言基本都是使用异常处理错误这是大势所趋 总结 以上就是本次关于C『异常』的全部内容了异常处理是软件开发中重要的错误管理工具本文深入探讨了异常的基本概念、C中的处理方式、使用技巧和异常体系设计。尽管异常提供了丰富的错误信息但其使用需要谨慎考虑执行流、性能开销等因素。在面对项目需求时程序员应权衡利弊以确保异常处理在提高代码可维护性和可靠性方面发挥最佳效果 相关文章推荐 C 进阶知识 C11『lambda表达式 ‖ 线程库 ‖ 包装器』 C11『右值引用 ‖ 完美转发 ‖ 新增类功能 ‖ 可变参数模板』 C11『基础新特性』 C11『右值引用与移动语义』 C11『基础新特性』 C 哈希的应用【布隆过滤器】 C 哈希的应用【位图】 C【哈希表的完善及封装】 C【哈希表的模拟实现】 C【初识哈希】 C【一棵红黑树封装 set 和 map】
http://www.pierceye.com/news/76392/

相关文章:

  • 当前网站建设的主要方法那个网站可以做ppt赚钱
  • 如何做一家网站巩义推广网站哪家好
  • 网站设计排版布局永州网站建设包括哪些
  • 静态网站没有数据库吗我做的网站怎么提升排名
  • 东莞建设工程公司seo自动工具
  • 视频网站代言人台州网页设计招聘信息
  • 怎么用wordpress打开网站吗个人注册公司在哪个网站申请
  • 洛宁网站开发奇璐荣获北京十大高端设计公司称号
  • 长春网站建设公司哪家好网站活动模板
  • nginx_lua wordpress南京seo排名扣费
  • 恩施网站优化新乡网站建设官网
  • 北京网站开发人员企业网站建设管理及推广
  • 黑龙江中国建设监理协会网站商标设计网站提供哪些服务
  • 如何建设网站appphp jsp开发网站开发
  • 定制网站建设提供商企业网站排名技巧
  • 枣庄网站制作费用表白网站怎样做有创意
  • 钢铁网站模板北京哪里做网站好
  • godaddy 搭建网站南昌建设局网站查询塔吊证
  • 免费pc网站建设网上做效果图网站有哪些
  • 潍坊模板建站定制wordpress娱乐插件
  • 做网站用什么主机好如何做市场营销推广
  • 青岛网站建设公司代理广州建网站的网络公司
  • 晋城市城乡建设局网站网站开发用什么架构
  • 加快政务网站群建设管理steam交易链接在哪
  • 自己做网站优化wordpress本地运行环境
  • 金马国旅网站建设分析网站备案流程阿里云
  • 建视频网站需要多少钱网站制作网站模板
  • 烟台公司网站建设恩施建设网站
  • 企业网站模板大全增城营销网站建设
  • 网站安全建设目的是什么网上申报办税系统