今天我们就来聊一聊 C++ 中的异常机制吧。
在学校期间,我们很少会用得上异常机制。然而,工作之后,很多时候却不得不引入异常机制。因为一般情况下,使用函数的返回值来确定函数的运行状态有缺陷:比如有些函数返回1表示成功,有些函数返回0表示成功。而且,一旦用一个整型表示错误码,函数结果就不能返回了(当然用指针和引用可以解决)。
1 如何正确访问 vector 中指定下标的元素
#include <IOStream>
#include <vector>
#include <stdexcept>
int main() {
std::vector<int> vec{1,2,3};
try {
char val1 = vec[100]; //数组下标越界访问
std::cout << val1 << "n";
} catch (std::exception e) {
std::cout << "[1]out of bound!" << "n";
}
try {
char val2 = vec.at(100);
std::cout << val2 << "n";
} catch (std::exception &e) {
std::cout << "[2]out of bound!" << "n";
}
}
执行结果:
第一个 try 没有捕获到异常,输出了一个没有意义的字符(垃圾值)。因为[ ]不会检查下标越界,不会抛出异常,所以即使有错误,try 也检测不到。换句话说,发生异常时必须将异常明确地抛出,try 才能检测到;如果不抛出来,即使有异常 try 也检测不到。所谓抛出异常,就是明确地告诉程序发生了什么错误。
第二个 try 检测到了异常,并交给 catch 处理,执行 catch 中的语句。需要说明的是,异常一旦抛出,会立刻被 try 检测到,并且不会再执行异常点(异常发生位置)后面的语句。本例中抛出异常的位置是 at() 函数,它后面的 cout 语句就不会再被执行,所以看不到它的输出。
2 自定义异常消息
#include <iostream>
#include <stdexcept>
#include <vector>
double f(int a, int b)
{
if (b == 0) {
throw "Division by zero";
}
return (a/b);
}
int main() {
try {
int a = 10;
int b = 0;
int v = f(1, b);
} catch (const char* msg) {
std::cerr << msg
<< "n";
}
return 0;
}
3 关键字 throw()
成员函数声明后面跟上throw(),表示告诉类的使用者:我的这个方法不会抛出异常,所以,在使用该方法的时候,不必把它至于 try/catch 异常处理块中。
声明一个不抛出异常的函数后,你有责任保证在你的函数的实现里面不会抛出异常。
最后,如果你想自定义一个异常,直接继承 exception 类,写个派生类即可。
#include <iostream>
#include <stdexcept>
#include <vector>
class Myexception:public std::exception{
};
int f(int a, int b) throw()
{
if(b == 0) throw Myexception(); // 程序会在这里崩溃.(如果该异常被处理,不会崩溃)
return a / b;
}
int main() {
try {
int a = 10;
int b = 0;
int v = f(1, b);
} catch (const char* msg) {
std::cerr << msg
<< "n";
}
return 0;
}
执行结果: