Back to VNotes

C++ / Syntax

现代 C++ 语法笔记(三)

整理原始字面量、long long、成员初始化、模板、异常等现代 C++ 语法点。

try-catch捕获异常

try块用于可能引发异常的代码,catch对异常进行捕获及处理

int main(){
	try{
		devide(10, 0);
	}
	catch(const char* e)
	{
		cout << "ERROR: " << e << endl;
	}
	return 0;
}

try中的代码称为保护代码,运行时可能抛出异常,然后异常会被catch接受,再进行处理

若有异常未能被捕获,程序会直接终止

try后可以跟很多个catch,抛出的异常会匹配对象类型相同且最近的catch,最后面可以加一个catch(...),接受任何类型的异常,防止有未被捕获的异常

栈展开:异常优先在当前函数栈中寻找匹配的catch,没有则退出到调用这层函数的栈,直到main函数,若依旧没找到则终止程序

自定义异常类:

class MyException{
	MyException(string s):msg(s){}
	string msg;
};

int devide(int a, int b)
{
	if(b == 0)
	{
		throw MyException("devide by zero");
	}
	int result = a/b;
	return result;
}

异常接口声明

使用throw()在函数声明是列出可能抛出的异常类型

int devide(int a, int b) throw(string, int)  //函数只能抛出这两种类型的异常
{                                            //若违反此声明,有些编译器会给出警告,有些直接编译失败
	if(b == 0)
	{
		throw "devide by zero";
	}
	int result = a/b;
	return result;
}
  • throw()修饰函数代表此函数不会抛出异常
  • 不写throw()代表此函数可能抛出任何类型的异常

异常处理会给程序带来一些微小的性能开销

noexcept

throw(类型)声明在C++11中被弃用,throw()声明不抛出异常也被noexcept关键字代替

int devide(int a, int b) noexcept  //此函数不会抛出异常
{                                            
	if(b == 0)
	{
		throw "devide by zero";
	}
	int result = a/b;
	return result;
}

noexcept还可以接受一个常量表达式作为参数

type function() noexcept(常量表达式){}

常量表达式:

  • 值为True,等于noexcept
  • 值为False,表示可能抛出异常

自动类型推导

auto

auto:声明为auto类型的变量在编译时由编译器自动推导类型

注意:

  • auto不是一种类型,而是类型声明的占位符
  • 使用auto来声明的变量必须初始化,否则编译器无法推导
  • 在下面的例子中,a与b的类型都是int\*,但声明a的auto被推导为int,和正常的声明一样,auto和\*要连在一起看,即为int*
int temp = 110;
auto *a = &temp;	
auto b = &temp;
  • 当变量不是指针或者引用类型时,推导的结果中不会保留const、volatile关键字

当变量是指针或者引用类型时,推导的结果中会保留const、volatile关键字

int tmp = 250;
const auto a1 = tmp;
auto a2 = a1;
const auto &a3 = tmp;
auto &a4 = a3;

​ 此处a2不是const,a3,a4是const

不能使用auto的场景:

  • 函数参数
  • 类的除静态常量成员变量(可以在类内初始化)以外的成员变量,与声明时要初始化矛盾
  • 数组
int array[] = {1,2,3,4,5};  
auto t1 = array;            
auto t2[] = array;         //XXX   
auto t3[] = {1,2,3,4,5};   //XXX
  • 模板参数
Test<auto> t1 = t;         //XXX

常用场景:

用于STL的容器遍历、泛型编程