try语句与异常处理
通常的异常处理包括三部分:
- throw表达式:使用throw表达式表示当前程序遇到了某个问题(异常声明)
- try语句块:与catch配合用于处理各类异常声明
- 一套异常类:用于传递具体的异常信息(异常声明的含义)
例程
1 |
|
throw表达式
1 | if(a!=b) throw runtime_error("ERROR!!!"); |
格式:throw+异常类+初始化异常类对象
该初始化的对象只用于提供一些关于异常的辅助信息(用户自行定义)
异常类为一系列在库中定义的类型,使用时需要声明其命名空间,以下是几种常用的异常类,在头文件stdexcept中
| exception | 一般错误 |
| :——————-: | :————————————————————: |
| runtime_error | 运行时才能检测出的任务 |
| range_error | 运行时:生成结果超出有意义的值域范围的错误 |
| overflow_error | 运行时:计算上溢错误 |
| underflow_error | 运行时:计算下溢错误 |
| logic_error | 程序逻辑错误 |
| domain_error | 逻辑错误:参数对应的结果不存在 |
| invalid_error | 逻辑错误:无效参数 |
| length_error | 逻辑错误:超出对象类型长度 |
| out_of_range | 逻辑错误:超出有效范围 |除exception外其他类型都必须用一个字符串初始化,而exception则不允许这种初始化
1
2
3
4
5
6
7
8
9try
{
if(a!=b) throw exception();
cout<<"good"<<endl;
}
catch(exception)
{
cout<<"ERROR!!";
}
try语句块
格式:
1 | try |
- 当try内一旦提出异常类时,就不再执行该throw表达式后的内容;反之,若没有throw任何异常,则不会触发任何catch语句,程序正常执行完try语句。
- catch括号中需定义一个对象,类型为触发的异常类,这些异常类只有一个子函数what,用于输出初始化时的字符串(不能用于exception类)
当有多个try语句块嵌套时,当最内部try提出了一个异常,会由内到外执行catch,若最终都没有对应catch,则程序转到terminate的标准库函数,该函数行为与系统有关,通常执行该函数会导致程序非正常退出。
函数
参数传递
- 形参实参之间的转递为值拷贝
- C++中建议用引用类型的形参代替指针形参,引用类型同样可以达到修改值的内容,并且可以避免拷贝,因为引用是与实参绑定的。
数组的传递
以下三种对形参的定义是等价的:
1 | void a(const int*); |
编译器在编译时只会检查传入的参数类型是否为const int*型,甚至不会检查传入数组的长度是否超出形参大小。
数组的引用形参
可以使用数组的引用作为形参:
1 | void test(int (&arr)[10]) |
使用数组的引用作为形参需要注意:
- 初始化时必须使用括号括起&arr
- 输入的实参必须为一个int [10]类型的对象
函数的返回类型
返回引用
函数返回引用可以理解为返回的为一个地址
1 | char test1(string s ,string::size_type num) |
当一个函数的返回值为引用时,该返回值为左值而非右值,因此可以像使用其他左值一样使用这个返回值
(注:左值≠地址,它仍然是一个值)
不可返回局部变量的引用,由于局部变量在函数完成后会被释放,因此在函数完成后引用会找不到它的对象。例如上一个例程,如果把test2()函数改为:
1
2
3
4
5
6
7
8
9
10
11char &test2(string s ,string::size_type num)//此处形参不再是引用
{
return s[num];
}
int main()
{
srting s("test");
test2(s,0)='a';
cout<<s[0]<<endl; //t
return 0;
}该函数的返回值为对s的引用,但s本身为一个局部变量,在函数完成时已经被释放,因此该引用是无效的(但是这样返回形参的引用编译器并不会报错,而返回函数内定义的局部变量的引用会报错)
但如果形参定义为引用,由于引用本身是不占用存储空间的,所以’a’可以通过引用直接向s[0]赋值
返回数组指针
尾置返回类型
1
auto func(int i) -> int(*)[10]
声明函数的返回值为一个含有十个整数的数组的指针
使用decltype
1
2
3
4
5
6
7
8
9
10int test[5]={1,2,3,4,5};
decltype(test) *func()
{
return &test;
}
int main()
{
cout<<*(*func+1); //输出2
return 0;
}- decltype(test)的结果是一个数组,因此函数前要用*声明返回值为指针
- 使用此方法返回的是一个数组的整体地址,而不是首地址,类型为int*[5],因此一次解引用的结果才是首地址
内联函数
正常的调用函数一般比等价的表达式要慢(保存寄存器、拷贝等操作),因此对于规模较小的函数可以定义为内联函数类型:
1 | inline int fuc(int a,int b) |
constexpr函数
将函数隐式地定义为内联函数,但函数内只能有一条return语句,且返回值必须为字面值