传统C/C++几种错误处理的方式

错误码

C语言强烈依赖于错误码来处理错误,包括以下几类:

  • 返回值
  • 输出参数
  • 错误单例(errno)

C语言的错误码通常是一个int类型,保持着底层的特性,没有任何的类型安全措施。

异常

C++继承了错误码的方式(因为它有许多调用C函数的地方),同时它也提出了新的错误传播方式-异常。
使用异常来处理错误有许多优势,因此它也被标准库所采用。
尽管异常有许多优势,错误码依然在广泛使用,包括在标准库当中。其中一个原因是考虑到和C语言的二进制兼容,但许多新的库依然更倾向于使用错误码而不是异常,有以下原因:

  • 使用异常,很难解释程序的控制流
  • 异常比错误码有更大的开销

第一个原因导致即使看起来只有一个return的函数,也可能因为异常有很多返回点,导致代码很难review,也很难被静态工具检查。
第二个原因在安全相关的系统中更关键,事实上,通过了ASIL认证的编译器都不支持异常,一个实际的例子是,C++的异常在处理时,使用了动态内存的分配,这个分配不可预测,并且时间不确定。
这些原因使得异常不适合汽车安全相关的系统。

不成功操作的类型

在实现AP的API过程中,不同的异常情况需要被检测到或者被报告,根据它们的特点,分为如下几种:

  • 错误:错误是假定bug-free的函数无法实现其功能,它可能是由于收到了无效输入,或非预期输入等,错误是可恢复的
  • 背离:背离是指应用程序框架的前置或后置条件失败的结果,AP中背离是对平台失败的断言,背离是无法恢复的
  • 损坏:损坏是指系统资源的损坏,比如栈溢出,内存错误,损坏是不可恢复的
  • 默认分配失败:指的是框架的默认内存分配机制无法满足分配,是不可恢复的

    AP中不成功操作的处理

    对于AP中不成功的操作,处理方式不同:

  • 对于错误的处理:函数应返回ara::core::Resultara::core::Future来处理错误

  • 对于背离的处理:背离有两种处理方式:
    • 抛出不是ara::core::Exception子类的异常
    • 调用ara::core::Abort终止进程
  • 对于损坏的处理:如果检测到损坏,应当导致不成功的进程终止,实现方式自定义
  • 对于默认分配失败得处理:和背离一样

    错误处理的设施

    ErrorCode

    就像名字所展示,ara::core::ErrorCode是错误码的一种形式,但是它是一个类类型(而不是传统的int),模仿的是std::error_code。与典型的C API使用的错误码相比,能处理更复杂的错误。
    它包含一个底层的错误值以及到错误域的引用。
    错误值是一个枚举类型,通常是带范围的。当存储在ara::core::ErrorCode中时,它的类型擦除到一个整型中,因此处理方式类似于C风格的错误值。错误域的引用定义了这个错误值的内容适用范围,提供了一些类型安全的机制。
    一个ara::core::ErrorCode也包含一个支持数据值,可以添加更多的数据到这个错误。
    ara::core::ErrorCode实例通常不会直接创建,而是通过ara::core::Result::FromError转发。
    一个ara::core::ErrorCode不局限于任何已知的错误域,它内部的类型擦除保证它很简单(非模板化),可以包含任意域的任意错误。
    然而,比较两个ara::core::ErrorCode实例只考虑错误值和错误域,支持数据值不检查是否相等,因为典型的判断场景是这样的: ```cpp ErrorCode ec = … if (ec == MyEnum::some_error) // … else if (ec == AnotherEnum::another_error) // …

``` 这些判断都会在右操作数建一个临时对象,不包含有意义的支持数据值

ErrorDomain

ara::core::ErrorDomain是一个抽象基类,它的派生类是定义在各FC或者APP内的特定错误域,这个类类似于std::error_category,但有不同的签名。
一个错误域有相关联的错误码枚举和相关的基础异常类型,它们通常都在同一个namespace内.
ara::core::ErrorDomain有一个uint64_t类型的ID,这个ID必须是唯一的,就代表了这个错误域,在跨ECU进行处理时,通过ID来判断错误域。

Result

ara::core::Result遵循了ValueOrError的概念,它要么包含一个值(ValueType类型),要么包含一个错误(ErrorType类型),ValueType和ErrorType都是ara::core::Result的模板参数,可以是任意类型,但ErrorType默认是ara::core::ErrorCode,并且希望贯穿于整个AP平台。
ara::core::Result表现为连接适用无异常API和有异常时ara::core::ErrorCode的包装类型,因为ara::core::ErrorCode和错误域特定的异常类型有直接的映射关系,ara::core::Result可以通过ValueOrThrow来抛出异常。

Future和Promise

ara::core::Futureara::core::Promise很像std::futurestd::promise,但是已经处理过ara::core::Reuslt的互操作。
ara::core::Future也是要么包含一个值,要么包含一个错误(即使是在ready状态)。
ara::core::Promise增加了一个SetError接口,来设置错误,相对应的,ara::core::Future也增加了新的函数GetResult,它和get很像,但不会抛出异常,而是返回一个ara::core::Result
因此ara::core::Future也有两种方式来处理错误,一种是通过异常,另一种是通过Result。
ara::core::Result用来处理同步函数调用的错误,而ara::core::Future用来处理异步调用