一、assert函数
(1)assert()函数-----专门为调试而准备的工具
(2)此函数在C语言的assert.h库文件里定义,所以好汉到C++程序里使用以下语句:
#include <cassert>
(3)assert()函数需要有一个参数,它将测试这个输入参数的真或者假状态。
– 如果为真, Do nothing !
– 如果为假, Do something !
(4)可以利用它在某个程序里的关键假设不成立时立刻停止该程序的执行并报错,从而避免发生 更严重的问题
(5)除了结合 assert ()函数,在程序的开发、测试阶段,我们还可以使用大量的 cout 语句来 报告在程序里正在发生的事情。
二、捕获异常
(1)最终用户看到的错误信息应该既专业又清晰,不能轻易中断程序,不能充满技术细节!
(2)为了对付潜在的编程错误(尤其是运行时的错误)
(3)基本使用思路:
- 安排一些 C++ 代码( try 语句)去尝试某件事—— 尤其是那些可能会失败的事(比如打开一个文件或申请一些内存)。
- 如果发生问题,就抛出一个异常( throm 语句)。
- 再安排一些代码( catch 语句)去捕获这个异常并进行相应的处理。
(4)基本语法
try
{
// Do something.
// Throw an exception on error.
}
catch
{
// Do whatever.
}
(5)注意
- 每条 try 语句至少要有一条配对的 catch 语句。
- 必须定义 catch 语句以便让它接收一个特定类型的参数。
- C++ 还允许我们定义多条 catch 语句,让每条catch 语句分别对应着一种可能的异常类型:
- catch ( int e ) { … }
- catch ( bool e ) { … }
- catch (…) { … }
- 最后一条 catch 语句可以捕获任何类型的异常
(6)throw保留字
- 在程序里,我们可以用 throw 保留字来抛出一个异常: throw 1;
- 在某个 try 语句块里执行过 throw 语句,它后面的所有语句(截止到这个 try 语句块末尾)将永远不会被执行。
(7)与使用一个条件语句或 return 语句相比,采用异常处理机制的好处是它可以把程序的正常功能和逻辑与出错处理部分清晰地划分开而不是让它们混杂在一起。
(8)如何让函数抛出异常
可以在定义一个函数时明确地表明你想让它抛出一个异常,为了表明你想让它抛出哪种类型的异常,可以使用如下所示语法:
type functionName(arguments) throw(type);
如果没有使用这种语法来定义函数,就意味着函数可以抛出任意类型的异常。
注:有些编译器不支持这种语法,则可省略throw(type) 部分。
(9)注意1
在构造器和析构器里不应该使用异常,稍有不慎就会导致严重的问题。
(10)注意2
- 如果 try 语句块无法找到一个与之匹配的 catch语句块,它抛出的异常将中止程序的执行。
- 在 C++ 标准库里有个一名为 exception 的文件,该文件声明了一个 exception 的基类。可以用这个基类来创建个人的子类以管理异常。而如此抛出和捕获的是exception 类或其子类的对象。
- 如果打算使用对象作为异常,请记住这样一个原则:以”值传递”方式抛出对象,以”引用传递”方式捕获对象。
(11)案例
1.
throw
关键字
throw
关键字的作用是抛出异常。在程序执行过程中,当遇到异常状况时,能够用throw
抛出一个异常对象。异常对象可以是任意类型,不过通常是类类型。2.
try
块
try
块用于包含可能会抛出异常的代码。在try
块中,若有异常被抛出,程序的控制权会马上转移到与之匹配的catch
块。3.
catch
块
catch
块用于捕获并处理try
块中抛出的异常。catch
块会依据异常对象的类型来匹配对应的异常。
#include <iostream>
// 定义一个函数,该函数可能会抛出异常
int divide(int a, int b) {
if (b == 0) {
// 当除数为0时,抛出一个字符串类型的异常
throw "Division by zero!";
}
return a / b;
}
int main() {
int num1 = 10;
int num2 = 0;
try {
// 尝试调用 divide 函数
int result = divide(num1, num2);
std::cout << "Result: " << result << std::endl;
} catch (const char* msg) {
// 捕获并处理抛出的异常
std::cerr << "Error: " << msg << std::endl;
}
return 0;
}
代码解释:
divide
函数接收两个整数作为参数,若第二个参数b
为 0,就会抛出一个字符串类型的异常"Division by zero!"
。- 在
main
函数中,把divide
函数的调用放在try
块里。若divide
函数抛出异常,程序会立即跳转到catch
块。 catch
块捕获的是const char*
类型的异常,并输出错误信息。
自定义异常类:
除了使用内置类型的异常,你还能自定义异常类。下面是一个自定义异常类的示例:
#include <iostream>
#include <stdexcept>
// 自定义异常类,继承自 std::exception
class MyException : public std::exception {
public:
const char* what() const noexcept override {
return "My custom exception occurred!";
}
};
// 定义一个函数,该函数可能会抛出自定义异常
void doSomething() {
throw MyException();
}
int main() {
try {
// 尝试调用 doSomething 函数
doSomething();
} catch (const MyException& e) {
// 捕获并处理自定义异常
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
代码解释:
MyException
类继承自std::exception
,并重写了what
方法,该方法返回一个描述异常信息的字符串。doSomething
函数抛出一个MyException
类型的异常。- 在
main
函数中,把doSomething
函数的调用放在try
块里,若抛出异常,会被catch
块捕获并处理。
未完待续。。。