C++异常和断言

C++异常

  • 异常的理念看似有前途,但实际的使用效果并不好。
  • 编程社区达成的一致意见是,最好不要使用这项功能。
  • C++98引入异常规范,C++11已弃用。
    例如:我们输入1时抛出异常。
#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {try {//可能抛出的异常的代码int ii = 0;cout << "我是一只小小鸟?(1-傻傻鸟;2-小小鸟)";cin >> ii;if (ii == 1) throw "不好,有人说我是一只傻傻鸟";//throw抛出异常cout << "我不是一只傻傻鸟,欧耶\n";}catch (...) {//不管什么异常,都在这里处理cout << "捕捉到异常,具体不管什么异常\n";}cout << "程序继续使用....\n";//执行完try..catch...后,将继续指向程序中其他代码return 0;
}
#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {try {//可能抛出的异常的代码int ii = 0;cout << "我是一只小小鸟?(1-傻傻鸟;2-小小鸟)";cin >> ii;if (ii == 1) throw "不好,有人说我是一只傻傻鸟";//throw抛出const char *类型异常if (ii == 2) throw ii;//throw抛出int类型异常if (ii == 3) throw string("不好,有人说我是一只傻傻鸟.");//throw抛出string类型异常cout << "我不是一只傻傻鸟,欧耶\n";}catch (int ii) {cout << "异常的类型是int=" << ii << endl;}catch (const char* ss) {cout << "异常的类型是const char*=" << ss << endl;}catch (string str) {cout << "异常的类型是string" << str << endl;}cout << "程序继续使用....\n";//执行完try..catch...后,将继续指向程序中其他代码return 0;
}

try语句块中,如果没有发生异常,执行完try语句块中的代码后,将继续执行try语句块之后的
代码;如果发生了异常,用throw抛出异常对象,异常对象的类型决定了应该匹配到哪个catch语句
块,如果没有匹配到catch语句块,程序将调用abort()函数中止
如果try语句块中用throw抛出异常对象,并且匹配到了catch语句块,执行完catch语句块中的
代码后,将继续执行catch语句块之后的代码,不会回到try语句块中。

如何避免异常

异常规范

C++98标准提出了异常规范,目的是为了让使用者知道函数可能会引发哪些异常。

void func1() throw(A, B,C);//表示该函数可能会抛出A、B、C类型的异常。
void func2() throw();//表示该函数不会抛出异常。
void func3();//该函数不符合C++98的异常规范。

C++11标准弃用了异常规范,使用新增的关键字noexcept指出函数不会引发异常。

void func4() noexcept;//该函数不会抛出异常。

在实际开发中,大部分程序员懒得在函数后面加noexcept,弃用异常已是共识,没必要多此一举。
关键字noexcept也可以用作运算符,判断表达试(操作数)是否可能引发异常;如果表达式可能引发异常,则返回false否则返回true。
在这里插入图片描述
对于下面的代码:

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {//分配一大块内存double* ptr = nullptr;try {ptr = new double[100000000000];}catch (bad_alloc& e) {cout << "分配内存失败\n";}return 0;
}

我们使用这种也行:

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {//分配一大块内存double* ptr = nullptr;ptr = new(std::nothrow) double[100000000000];if (ptr == nullptr)cout << "分配内存失败\n";//其他处理业务代码if (ptr != nullptr) delete[]ptr;return 0;
}

我们在实际开发中经常用这种,这种比较简单。

重点关注的异常

  1. std::bad_alloc
    如果内存不足,调用new会产生异常,导致程序中止;如果在new关键字后面加(std:nothrow)选项,则返回nullptr,不会产生异常。

  2. dynamic_cast
    dynamic_cast可以用于引用,但是,没有与空指针对应的引用值,如果转换请求不正确,会出现
    td::bad_cast异常。

  3. std:bad_typeid
    假设有表达式typeid(*ptr),当ptr是空指针时,如果ptr是多态的类型,将引发std:bad_typeid异常。

逻辑错误异常

程序的逻辑错误产生的异常std::logic_error,通过合理的编程可以避免。

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {try {vector<int>vv = { 1,2,3 };//容器vv中只有三个元素vv.at(3) = 5;//将引发out_of_range异常}catch (out_of_range) {cout << "出现out_of_range异常\n";}return 0;
}
#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {//string str="123";//不会抛出异常//string str="";//将抛出Invalid_argument异常string str = "21212312312313123123123";//将抛出out_of_range异常try {int x = stoi(str);//将string字符串转化为整数cout << "x=" << x << endl;}catch (invalid_argument&) {cout << "出现invalid_argument异常\n";}catch (out_of_range&) {cout << "出现out_of_range异常\n";}return 0;
}

这个逻辑异常应该有程序员自己解决

C++断言

断言(assertion)是一种常用的编程手段,用于排除程序中不应该出现的逻辑错误。
使用断言需要包含头文件<cassert><assert.h>,头文件中提供了带参数的宏assert,用于程序
在运行时进行断言。

语法:assert(表达式);

断言就是判断(表达式)的值,如果为0(false),程序将调用abort()函数中止,如果为非0 (true),程序继续执行。
断言可以提高程序的可读性,帮助程序员定位违反了某些前提条件的错误。
例如:

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
#include<cassert>
using namespace std;
void copydata(void* ptr1, void* ptr2) {//把ptr2中的数据复制到ptr1中。assert(ptr1 && ptr2);//断言ptr1和ptr2都不会为空cout << "继续执行复制数据的代码....\n";}
int main() {int ii = 0, jj = 0;copydata(&ii, &jj);//把ptr2中的数据复制到ptr1中。return 0;
}

这个是正常的,就是把jj中的数据复制到ii中。
假如是这个代码:

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
#include<cassert>
using namespace std;
void copydata(void* ptr1, void* ptr2) {//把ptr2中的数据复制到ptr1中。assert(ptr1 && ptr2);//断言ptr1和ptr2都不会为空cout << "继续执行复制数据的代码....\n";}
int main() {int ii = 0, jj = 0;copydata(nullptr, &jj);//把ptr2中的数据复制到ptr1中。return 0;
}

在这里插入图片描述
注意:

  • 断言用于处理程序中不应该发生的错误,而非逻辑上可能会发生的错误。
  • 不要把需要执行的代码放到断言的表达式中。
  • 断言的代码一般放在函数/成员函数的第一行,表达式多为函数的形参,主要用于判断参数是否参数的合法性。

C++11 静态断言

assert宏是运行时断言,在程序运行的时候才能起作用。
C++11新增了静态断言static_assert,用于在编译时检查源代码。
使用静态断言不需要包含头文件。
语法: static_assert(常量表达式,提示信息);
用途: 在编译的时候,判断常量表达式的值,如果是0-false,那么编译失败,否则显示提示信息。
注意: static_assert的第一个参数是常量表达式。而assert 的表达式既可以是常量,也可以是变
量。

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
#include<cassert>
using namespace std;
void copydata(void* ptr1, void* ptr2) {//把ptr2中的数据复制到ptr1中。assert(ptr1 && ptr2);//断言ptr1和ptr2都不会为空cout << "继续执行复制数据的代码....\n";}
int main() {const int ii = 1, jj = 0;assert(ii);static_assert(ii, "ii的值不合法。");//copydata(nullptr, &jj);//把ptr2中的数据复制到ptr1中。return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/641058.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

牛客网刷题 | BC60 判断是不是字母

描述 KiKi想判断输入的字符是不是字母&#xff0c;请帮他编程实现。 输入描述&#xff1a; 多组输入&#xff0c;每一行输入一个字符。 输出描述&#xff1a; 针对每组输入&#xff0c;输出单独占一行&#xff0c;判断输入字符是否为字母&#xff0c;输出内容详见输出样例…

Java中使用Graphics2D绘制字符串文本自动换行 算法

效果&#xff1a; 代码&#xff1a; /*** return void* Author xia* Description //TODO 写字换行算法* Date 18:08 2021/4/1* Param []**/private static void drawWordAndLineFeed(Graphics2D g2d, Font font, String words, int wordsX, int wordsY, int wordsWidth) {FontD…

Tensorflow AutoGraph 的作用和功能

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ TensorFlow AutoGraph 是 TensorFlow 中的一个重要特性&#xff0c;它允许开发者使用普通的 Python 语法编写高效的 TensorFlow 图&#xff08;graph&#xff09;。这意味着开发者可以利用 Python 的易…

Nodejs 第六十七章(OpenAI)

OpenAI OpenAI是一个人工智能研究实验室和技术公司&#xff0c;致力于推动人工智能的发展和应用 OpenAI最著名的项目之一是GPT&#xff08;Generative Pre-trained Transformer&#xff09;系列模型&#xff0c;其中包括了GPT-3&#xff0c;它是迄今为止最大规模的语言模型之…

【Docker】Docker基本操作

docker 发展历史 https://www.cnblogs.com/rongba/articles/14782624.html Docker概述 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。 Docker 的容…

《王者荣耀》Hello Kitty 小兵皮肤完整设置指南

王者荣耀与三丽鸥的联动活动上线了 Hello Kitty 小兵皮肤&#xff0c;让我们的峡谷小兵们也能穿上漂亮的衣服啦&#xff01;这款皮肤极具卡哇伊风格&#xff0c;引起了许多玩家的关注。许多小伙伴都想知道如何使用这款 Hello Kitty 小兵皮肤&#xff0c;今天小编将为大家整理出…

快速部署stable diffusion@Ubuntu

Stable Diffusion可以根据文本描述生成相关的图像&#xff0c;是当前最热门的文生图模型。 在Ubuntu下&#xff0c;可以选择快速安装&#xff0c;或者手动一步步安装。 快速安装 使用文档中的方法&#xff0c;先下载一个sh文件&#xff0c;然后执行这个文件&#xff0c;就自动…

循环神经网络实例——序列预测

我们生活的世界充满了形形色色的序列数据&#xff0c;只要是有顺序的数据统统都可以看作是序列数据&#xff0c;比如文字是字符的序列&#xff0c;音乐是音符组成的序列&#xff0c;股价数据也是序列&#xff0c;连DNA序列也属于序列数据。循环神经网络RNN天生就具有处理序列数…

初识Docker-概念、安装和使用

摘要&#xff1a;这里整理了下Docker的基本概念、安装&#xff08;包括CentOS和MacOS&#xff09;过程以及常用命令&#xff0c;记录下... Docker 是一种开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中&#xff0c;然后发布到…

Ps 滤镜:波浪

Ps菜单&#xff1a;滤镜/扭曲/波浪 Filter/Distort/Wave 波浪 Wave滤镜可以在图像上创建复杂且可控的波浪形变效果。此滤镜提供了丰富的选项&#xff0c;可以精确调整波浪的形状、大小和分布&#xff0c;以实现不同的视觉效果。 “波浪”滤镜通过对图像应用数学波形函数来扭曲图…

【PhpStorm的环境配置与应用的简单介绍】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Redis入门到通关之数据结构解析-QuickList

文章目录 ☃️前提概要☃️ 配置项相关☃️简要源码☃️总结 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与空间的平衡&#xff0c;0与1…