在std中,可以使用cerr打印异常

std::cin >> a;
if(a == 0){
    std::cerr << "division by zero!" << std::endl;
}

程序退出 Program Termination

1. return

2. exit()

使用exit()函数退出程序,exit(0)意味着程序运行成功,正常退出。

int main() {
     int a;
     cin >> a;
     if (a == 0) {
         cerr << "division by zero!" << endl;
         exit(-1);
     }
     cout << 10 / a << endl;
     return 0;
 }

和return的区别:return类似与continue,break这样的关键词,用于返回函数值;而exit是直接退出程序。在main函数中,二者基本没有区别,都可用于结束程序。

3. abort()

abort()函数也可用于退出程序。

abort()与exit()的区别

#include <iostream>
using namespace std;

class Function{
public:
    Function(){
        cout << "Function constructor called" << endl;
    }
    ~Function(){
        cout << "Function destructor called" << endl;
    }
};

int main(){
    Function f1;
    exit(0);
    return 0;
}

Output:
Function constructor called

#include <iostream>
using namespace std;

class Function{
public:
    Function(){
        cout << "Function constructor called" << endl;
    }
    ~Function(){
        cout << "Function destructor called" << endl;
    }
};
Function f1;
int main(){
    exit(0);
    return 0;
}

Output:
Function constructor called
Function destructor called

由此可见,exit()函数可以调用析构函数,但自动对象的析构函数不会被调用。(自动对象:在子程序或block中分配的对象,详见https://www.ibm.com/docs/en/xl-fortran-linux/16.1.0?topic=objects-automatic

而abort()函数完全不会调用析构函数。

断言 Assertion

需要#include <cassert>

用法:

#include<iostream>
#include<cassert>
using namespace std;
int main() {
    assert(1 == 0);
    return 0;
}
PS D:\2023-2024\course-oop\test> .\test.exe
Assertion failed: 1 == 0, file check.cpp, line 5

如果断言错误,则程序立刻停止。

可以使用 #define NDEBUG 忽略断言。

异常和错误 Exception

c++中异常处理包含:try,throw,catch

可以通过try定义一段代码,以便在执行时测试是否存在错误。

用法:

#include <iostream>
int main(){
    std::string str("foo");
    try{
        str.at(10); // 抛出 out_of_range 异常
    }catch(const std::out_of_range& e){
        std::cout << "out_of_range: " << e.what() << std::endl; // what() 返回异常的描述信息
        // 这里捕获的是 std::exception 的子类 std::out_of_range 异常
    }catch(const std::exception& e){ // 当然,也可以捕获其他异常
        std::cout << "exception: " << e.what() << std::endl;
    }
    return 0;
}

实际用例:

在这里,我们定义了一个时间的class,同时需要保证小时数和分钟数是正确的格式。故当时间输入不合规时,可以抛出(throw)一个异常,并在其他地方捕获(catch)

catch有一个参数。当catch里面的参数与throw抛出的参数相同时,会执行catch代码块中的内容。

可以使用多个catch来捕获不同的异常

int main(){
    try{

    }catch(type1& e1){

    }catch(type2& e2){

    }catch(...){
        //如果不清楚错误类型,可以使用catch(...)代替
    }
    return 0;
}

详见:https://www.w3schools.com/cpp/cpp_exceptions.asp