# AUTOSAR C++ 2014 规范


# AUTOSAR Cpp 2014 规范

> [https://ww2.mathworks.cn/help/bugfinder/autosar-c-14.html?lang=en](https://ww2.mathworks.cn/help/bugfinder/autosar-c-14.html?lang=en)

**[English Version](./004_AutosarCpp2014规范英文版.md)**

----

## 语言无关性问题

[规则 A0-1-1] 项目中不得出现为非易失性变量赋值后，该值后续未被使用的情况。

[规则 A0-1-2] 非重载运算符、且返回类型非 `void` 的函数，其返回值必须被使用。

[规则 A0-1-3] 匿名命名空间中定义的所有函数、具有内部链接性的静态函数、私有成员函数，都必须被使用。

[规则 A0-1-4] 非虚函数中不得存在未使用的命名参数。

[规则 A0-1-5] 虚函数及其所有重写函数的参数集合中，不得存在未使用的命名参数。

[规则 A0-1-6] 不应存在未使用的类型声明。

[规则 A0-4-2] 不得使用 `long double` 类型。

[规则 A0-4-4] 使用数学函数时，必须对范围错误、定义域错误和极点错误进行检查。

[规则 M0-1-1] 项目中不得存在不可达代码。

[规则 M0-1-2] 项目中不得存在不可执行路径。

[规则 M0-1-3] 项目中不得存在未使用的变量。

[规则 M0-1-4] 项目中不得存在仅被使用一次的非易失性 `POD` 变量。

[规则 M0-1-8] 所有返回类型为 void 的函数，必须具备外部副作用。

[规则 M0-1-9] 不得存在死代码。

[规则 M0-1-10] 每个已定义的函数都应至少被调用一次。

[规则 M0-2-1] 不得将对象赋值给内存重叠的对象。

[规则 M0-3-2] 若函数会生成错误信息，则必须对该错误信息进行检测。

----

## 通用原则

[规则 A1-1-1] 所有代码必须符合《`ISO/IEC 14882:2014` C++ 编程语言》标准，且不得使用已弃用的特性。

----

## 词法约定

[规则 A2-3-1] 源代码中只能使用 `C++` 语言标准基础源字符集中规定的字符。

[规则 A2-5-1] 不得使用三字符组。

[规则 A2-5-2] 不得使用双字符组。

[规则 A2-7-1] 反斜杠 `\` 不得出现在 `C++` 注释的末尾。

[规则 A2-7-2] 不得通过 “注释掉” 的方式屏蔽代码段。

[规则 A2-7-3] 所有 “用户自定义” 类型、静态与非静态数据成员、函数及方法的声明前，必须附带文档说明。

[规则 A2-8-1] 头文件名应能体现其声明内容对应的逻辑实体。

[规则 A2-8-2] 实现文件名应能体现其定义内容对应的逻辑实体。

[规则 A2-10-1] 内层作用域中声明的标识符，不得隐藏外层作用域中声明的标识符。

[规则 A2-10-4] 具有静态存储期的非成员对象或静态函数的标识符名称，不得在同一命名空间内重复使用。

[规则 A2-10-5] 具有静态存储期的函数、具有外部或内部链接性的非成员对象的标识符名称，不应重复使用。

[规则 A2-10-6] 类或枚举名称，不得被同一作用域中的变量、函数或枚举常量声明所隐藏。

[规则 A2-11-1] 不得使用 `volatile` 关键字。

[规则 A2-13-1] 只能使用 `ISO/IEC 14882:2014` 标准中定义的转义序列。

[规则 A2-13-2] 不得拼接具有不同编码前缀的字符串字面量。

[规则 A2-13-3] 不得使用 `wchar_t` 类型。

[规则 A2-13-4] 不得将字符串字面量赋值给非 `const` 指针。

[规则 A2-13-5] 十六进制常量应使用大写形式。

[规则 A2-13-6] 通用字符名只能在字符或字符串字面量内部使用。

[规则 M2-7-1] `C` 风格注释中不得出现 `/*` 字符序列。

[规则 M2-10-1] 不同的标识符在排版上必须无歧义。

[规则 M2-13-2] 不得使用零以外的八进制常量，以及 `\0` 以外的八进制转义序列。

[规则 M2-13-3] 所有无符号类型的八进制或十六进制整数字面量，都必须添加 `U` 后缀。

[规则 M2-13-4] 字面量后缀必须使用大写形式。

----

## 基础概念

[规则 A3-1-1] 所有头文件必须支持在多个翻译单元中引入，且不违反单一定义规则（`ODR`）。

[规则 A3-1-2] 项目中本地定义的头文件，文件扩展名必须为 `.h`、`.hpp` 或 `.hxx` 其中之一。

[规则 A3-1-3] 项目中本地定义的实现文件，文件扩展名应为 `.cpp`。

[规则 A3-1-4] 声明具有外部链接性的数组时，必须显式指定其大小。

[规则 A3-1-5] 函数定义仅在满足以下任一条件时，才能放置在类定义内部：(1) 函数需要被内联；(2) 是成员函数模板；(3) 是类模板的成员函数。

[规则 A3-1-6] 简单的读取和修改器函数应被内联。

[规则 A3-3-1] 具有外部链接性的对象或函数（包括具名命名空间的成员），必须在头文件中声明。

[规则 A3-3-2] 静态对象和线程局部对象必须进行常量初始化。

[规则 A3-8-1] 不得在对象的生命周期之外访问该对象。

[规则 A3-9-1] 必须使用 `<cstdint>` 头文件中定义的、明确指明大小和符号性的定宽整数类型，替代基础数值类型。

[规则 M3-1-2] 不得在块作用域中声明函数。

[规则 M3-2-1] 同一对象或函数的所有声明，必须具有兼容的类型。

[规则 M3-2-2] 不得违反单一定义规则。

[规则 M3-2-3] 在多个翻译单元中使用的类型、对象或函数，必须且只能在一个文件中声明。

[规则 M3-2-4] 具有外部链接性的标识符，必须有且仅有一个定义。

[规则 M3-3-2] 若函数具有内部链接性，则其所有重声明都必须包含 `static` 存储类说明符。

[规则 M3-4-1] 声明为对象或类型的标识符，必须在能最小化其可见性的块中定义。

[规则 M3-9-1] 对象类型、函数返回类型、函数参数所使用的类型，在所有声明和重声明中，必须逐标记完全一致。

[规则 M3-9-3] 不得使用浮点值的底层二进制位表示。

----

## 标准约定

[规则 A4-5-1] `enum` 或 `enum class` 类型的表达式，不得作为以下运算符之外的内置及重载运算符的操作数：下标运算符 `[]`、赋值运算符 `=`、相等运算符 `==` 与 `!=`、取地址运算符 `&`、关系运算符 `<`、`<=`、`>`、`>=`。

[规则 A4-7-1] 整数表达式不得导致数据丢失。

[规则 A4-10-1] 只能使用 `nullptr` 字面量作为空指针常量。

[规则 M4-5-1] `bool` 类型的表达式，不得作为以下运算符之外的内置运算符的操作数：赋值运算符 `=`、逻辑运算符 `&&`、`||`、`!`、相等运算符 `==` 与 `!=`、取地址运算符 `&`、条件运算符。

[规则 M4-5-3] 普通 `char` 类型与 `wchar_t` 类型的表达式，不得作为以下运算符之外的内置运算符的操作数：赋值运算符 `=`、相等运算符 `==` 与 `!=`、取地址运算符 `&`。

[规则 M4-10-1] 不得将 `NULL` 用作整数值。

[规则 M4-10-2] 不得将字面量零 (`0`) 用作空指针常量。

----

## 表达式

[规则 A5-0-1] 表达式的求值结果，在标准允许的任意求值顺序下必须保持一致。

[规则 A5-0-2] `if` 语句的条件与循环语句的条件，必须为 `bool` 类型。

[规则 A5-0-3] 对象声明中，指针的间接寻址层级不得超过两层。

[规则 A5-0-4] 指针算术运算不得作用于指向非 `final` 类的指针。

[规则 A5-1-1] 除类型初始化外，不得直接使用字面量值，应使用符号名称替代。

[规则 A5-1-2] `lambda` 表达式中不得隐式捕获变量。

[规则 A5-1-3] 每个 `lambda` 表达式都必须包含参数列表（可为空）。

[规则 A5-1-4] `lambda` 表达式对象的生命周期，不得超过其任何按引用捕获的对象的生命周期。

[规则 A5-1-6] 返回类型非 `void` 的 `lambda` 表达式，应显式指定返回类型。

[规则 A5-1-7] `lambda` 不得作为 `decltype` 或 `typeid` 的操作数。

[规则 A5-1-8] 不应在另一个 `lambda` 表达式内部定义 `lambda` 表达式。

[规则 A5-1-9] 相同的匿名 `lambda` 表达式，应替换为具名函数或具名 `lambda` 表达式。

[规则 A5-2-1] 不应使用 `dynamic_cast`。

[规则 A5-2-2] 不得使用传统的 `C` 风格强制类型转换。

[规则 A5-2-3] 强制类型转换不得移除指针或引用类型的 `const` 或 `volatile` 限定。

[规则 A5-2-4] 不得使用 `reinterpret_cast`。

[规则 A5-2-5] 不得越界访问数组或容器。

[规则 A5-2-6] 逻辑与 `&&`、逻辑或 `||` 的操作数若包含二元运算符，必须为操作数添加括号。

[规则 A5-3-1] `typeid` 运算符的操作数求值过程，不得产生副作用。

[规则 A5-3-2] 不得解引用空指针。

[规则 A5-3-3] 不得删除指向不完整类类型的指针。

[规则 A5-5-1] 指向成员的指针，不得访问类中不存在的成员。

[规则 A5-6-1] 整数除法或取余运算符的右操作数不得为零。

[规则 A5-10-1] 指向虚成员函数的成员指针，仅能与空指针常量进行相等性判断。

[规则 A5-16-1] 三元条件运算符不得作为子表达式使用。

[规则 M5-0-2] 表达式中应尽量减少对 `C++` 运算符优先级规则的依赖。

[规则 M5-0-3] 左值表达式不得被隐式转换为不同的底层类型。

[规则 M5-0-4] 隐式整数转换不得改变底层类型的符号性。

[规则 M5-0-5] 不得进行浮点与整数类型之间的隐式转换。

[规则 M5-0-6] 隐式整数或浮点转换不得缩减底层类型的大小。

[规则 M5-0-7] 不得对左值表达式进行浮点与整数类型之间的显式转换。

[规则 M5-0-8] 显式整数或浮点转换不得扩大左值表达式底层类型的大小。

[规则 M5-0-9] 显式整数转换不得改变左值表达式底层类型的符号性。

[规则 M5-0-10] 若按位取反 `~` 和左移 `<<` 运算符作用于底层类型为 `unsigned char` 或 `unsigned short` 的操作数，其结果必须立即转换回操作数的底层类型。

[规则 M5-0-11] 普通 `char` 类型仅可用于字符值的存储与使用。

[规则 M5-0-12] `signed char` 与 `unsigned char` 类型仅可用于数值的存储与使用。

[规则 M5-0-14] 条件运算符的第一个操作数必须为 `bool` 类型。

[规则 M5-0-15] 数组下标是唯一允许使用的指针算术运算形式。

[规则 M5-0-16] 指针算术运算中的原始指针操作数，以及运算生成的结果指针，都必须指向同一数组的元素。

[规则 M5-0-17] 指针之间的减法运算，仅能作用于指向同一数组元素的指针。

[规则 M5-0-18] 除指向同一数组的情况外，`>`、`>=`、`<`、`<=` 运算符不得作用于指针对象。

[规则 M5-0-20] 二元位运算符的非常量操作数，必须具有相同的底层类型。

[规则 M5-0-21] 位运算符仅能作用于无符号底层类型的操作数。

[规则 M5-2-2] 指向虚基类的指针，仅能通过 `dynamic_cast` 转换为指向派生类的指针。

[规则 M5-2-3] 多态类型不应执行从基类到派生类的强制类型转换。

[规则 M5-2-6] 不得将函数指针转换为任何其他指针类型，包括其他函数指针类型。

[规则 M5-2-8] 不得将整数类型对象或 `void` 类型指针转换为指针类型对象。

[规则 M5-2-9] 不得将指针类型转换为整数类型。

[规则 M5-2-10] 自增 (`++`) 和自减 (`--`) 运算符不得与表达式中的其他运算符混用。

[规则 M5-2-11] 不得重载逗号运算符、`&&` 运算符和 `||` 运算符。

[规则 M5-2-12] 作为函数参数传递的数组类型标识符，不得退化为指针。

[规则 M5-3-1] 逻辑非 `!` 运算符、逻辑与 `&&`、逻辑或 `||` 运算符的每个操作数，都必须为 `bool` 类型。

[规则 M5-3-2] 一元负号运算符不得作用于底层类型为无符号的表达式。

[规则 M5-3-3] 不得重载取地址 `&` 运算符。

[规则 M5-3-4] `sizeof` 运算符的操作数求值过程，不得产生副作用。

[规则 M5-8-1] 移位运算符的右操作数，必须大于等于 `0`，且小于左操作数底层类型的位宽。

[规则 M5-14-1] 逻辑与 `&&`、逻辑或 `||` 运算符的右操作数，不得产生副作用。

[规则 M5-18-1] 不得使用逗号运算符。

[规则 M5-19-1] 无符号整数常量表达式的求值不得发生回绕。

----

## 语句

[规则 A6-2-1] 移动与拷贝赋值运算符，必须仅对类的基类和数据成员执行对应的移动或拷贝操作，不得产生任何额外副作用。

[规则 A6-2-2] 表达式语句不得仅为临时对象构造函数的显式调用。

[规则 A6-4-1] `switch` 语句必须包含至少两个与 `default` 标签不同的 `case` 分支。

[规则 A6-5-1] 若 `for` 循环遍历容器的所有元素，且未使用循环计数器，则不得使用该 `for` 循环。

[规则 A6-5-2] `for` 循环必须包含唯一的循环计数器，且循环计数器不得为浮点类型。

[规则 A6-5-3] 不应使用 `do-while` 语句。

[规则 A6-5-4] `for` 循环的初始化语句和循环表达式，不得执行循环计数器初始化与修改之外的操作。

[规则 A6-6-1] 不得使用 `goto` 语句。

[规则 M6-2-1] 赋值运算符不得在子表达式中使用。

[规则 M6-2-2] 不得直接或间接对浮点表达式进行相等或不等判断。

[规则 M6-2-3] 预处理前，空语句必须单独占一行；其后可跟随注释，但空语句后的第一个字符必须为空白字符。

[规则 M6-3-1] `switch`、`while`、`do-while` 或 `for` 语句的循环体语句，必须为复合语句。

[规则 M6-4-1] `if` (条件) 结构后必须跟随复合语句；`else` 关键字后必须跟随复合语句或另一个 `if` 语句。

[规则 M6-4-2] 所有 `if...else if` 结构必须以 `else` 子句结尾。

[规则 M6-4-3] `switch` 语句必须是格式良好的 `switch` 语句。

[规则 M6-4-4] `switch` 标签仅能在最内层闭合的复合语句为 `switch` 语句体时使用。

[规则 M6-4-5] 每个非空的 `switch` 分支，必须以无条件的 `throw` 或 `break` 语句终止。

[规则 M6-4-6] `switch` 语句的最后一个分支必须是 `default` 分支。

[规则 M6-4-7] `switch` 语句的条件不得为 `bool` 类型。

[规则 M6-5-2] 若循环计数器未通过 `--` 或 `++` 修改，则在循环条件中，循环计数器仅能作为 `<=`、`<`、`>`、`>=` 运算符的操作数。

[规则 M6-5-3] 不得在循环条件或循环体中修改循环计数器。

[规则 M6-5-4] 循环计数器仅能通过以下操作修改：`--`、`++`、`-=n` 或 `+=n`；其中 `n` 在循环执行期间必须保持恒定。

[规则 M6-5-5] 循环控制变量中，除循环计数器外的其他变量，不得在循环条件或循环表达式中修改。

[规则 M6-5-6] 循环控制变量中，除循环计数器外、在循环体中被修改的变量，必须为 `bool` 类型。

[规则 M6-6-1] `goto` 语句引用的任何标签，必须在同一代码块中，或在包含该 `goto` 语句的代码块中声明。

[规则 M6-6-2] `goto` 语句必须跳转到同一函数体中、声明在其后方的标签。

[规则 M6-6-3] `continue` 语句仅能在格式良好的 `for` 循环中使用。

----

## 声明

[规则 A7-1-1] 不可变数据的声明必须使用 `constexpr` 或 `const` 说明符。

[规则 A7-1-2] 编译期可确定的值，必须使用 `constexpr` 说明符。

[规则 A7-1-3] `CV` 限定符必须放置在 `typedef` 或 `using` 定义的类型名称的右侧。

[规则 A7-1-4] 不得使用 `register` 关键字。

[规则 A7-1-5] `auto` 说明符仅能在以下场景中使用：(1) 声明变量的类型与函数调用的返回类型一致；(2) 声明变量的类型与非基础类型的初始化值类型一致；(3) 声明泛型 `lambda` 表达式的参数；(4) 使用尾置返回类型语法声明函数模板。

[规则 A7-1-6] 不得使用 `typedef` 说明符。

[规则 A7-1-7] 每个表达式语句和标识符声明，必须单独占一行。

[规则 A7-1-8] 声明中，非类型说明符必须放置在类型说明符之前。

[规则 A7-1-9] 类、结构体或枚举不得在其类型定义中声明。

[规则 A7-2-1] 枚举底层类型的表达式，其值只能对应枚举的枚举常量。

[规则 A7-2-2] 必须显式定义枚举的底层类型。

[规则 A7-2-3] 枚举必须声明为带作用域的枚举类（`enum class`）。

[规则 A7-2-4] 枚举中，必须满足以下三种情况之一：(1) 所有枚举常量都不初始化；(2) 仅第一个枚举常量初始化；(3) 所有枚举常量都初始化。

[规则 A7-3-1] 函数的所有重载版本，在调用处必须可见。

[规则 A7-5-1] 函数不得返回指向 `const` 引用传递的参数的引用或指针。

[规则 A7-5-2] 函数不得直接或间接调用自身。

[规则 A7-6-1] 声明了 `[[noreturn]]` 属性的函数不得返回。

[规则 M7-1-2] 函数中的指针或引用类型参数，若对应的对象在函数内不会被修改，必须声明为指向 `const` 的指针或 `const` 引用。

[规则 M7-3-1] 全局命名空间中只能包含 `main` 函数、命名空间声明和 `extern "C"` 声明。

[规则 M7-3-2] `main` 标识符不得用于全局 `main` 函数之外的其他函数。

[规则 M7-3-3] 头文件中不得出现匿名命名空间。

[规则 M7-3-4] 不得使用 `using` 指令（`using-directives`）。

[规则 M7-3-6] 头文件中不得使用 `using` 指令和 `using` 声明（类作用域或函数作用域内的 `using` 声明除外）。

[规则 A7-4-1] 不得使用 `asm` 声明。

[规则 M7-4-2] 汇编指令只能通过 `asm` 声明引入。

[规则 M7-4-3] 汇编代码必须进行封装与隔离。

[规则 M7-5-1] 函数不得返回指向其内部定义的自动变量（包括参数）的引用或指针。

[规则 M7-5-2] 自动存储期对象的地址，不得赋值给在该对象销毁后仍可能存在的其他对象。

----

## 声明符

[规则 A8-2-1] 声明函数模板时，若返回类型依赖于参数类型，必须使用尾置返回类型语法。

[规则 A8-4-1] 不得使用省略号语法定义函数。

[规则 A8-4-2] 返回类型非 `void` 的函数，其所有退出路径都必须带有表达式的显式 return 语句。

[规则 A8-4-3] 应使用通用的参数传递方式。

[规则 A8-4-4] 函数的多个返回值应通过结构体或元组返回。

[规则 A8-4-5] 声明为 `X &&` 的 “消费型” 参数，必须始终对其执行移动操作。

[规则 A8-4-6] 声明为 `T &&` 的 “转发型” 参数，必须始终对其执行完美转发。

[规则 A8-4-7] “入参” 类型若拷贝成本低，应按值传递。

[规则 A8-4-8] 不得使用输出型参数。

[规则 A8-4-9] 声明为 `T &` 的 “入出型” 参数，在函数内必须被修改。

[规则 A8-4-10] 若参数不可为 `NULL`，必须按引用传递。

[规则 A8-4-11] 智能指针仅在需要表达生命周期语义时，才能作为参数类型使用。

[规则 A8-4-12] `std::unique_ptr` 传递给函数时，仅能采用以下两种形式：(1) 按值拷贝，表达函数接管所有权；(2) 左值引用，表达函数会替换其管理的对象。

[规则 A8-4-13] `std::shared_ptr` 传递给函数时，仅能采用以下三种形式：(1) 按值拷贝，表达函数共享所有权；(2) 左值引用，表达函数会替换其管理的对象；(3) `const` 左值引用，表达函数会保留其引用计数。

[规则 A8-4-14] 接口必须具备精确的强类型定义。

[规则 A8-5-0] 所有内存必须在读取前完成初始化。

[规则 A8-5-1] 初始化列表必须遵循以下初始化顺序：(1) 按继承图的深度优先、从左到右顺序初始化虚基类；(2) 按继承列表从左到右顺序初始化直接基类；(3) 按类定义中的声明顺序初始化非静态数据成员。

[规则 A8-5-2] 变量初始化必须使用不带等号的大括号列表初始化 `{}`。

[规则 A8-5-4] 若类的用户声明构造函数包含 `std::initializer_list` 类型的参数，则该类除特殊成员函数外，只能拥有这一个构造函数。

[规则 A8-5-3] `auto` 类型的变量不得使用 `{}` 或 `={}` 的大括号初始化方式。

[规则 M8-0-1] 一个初始化声明符列表或成员声明符列表，必须仅包含一个初始化声明符或成员声明符。

[规则 M8-3-1] 重写的虚函数中的参数，要么使用与被重写函数完全相同的默认实参，要么不指定任何默认实参。

[规则 M8-4-2] 函数重声明中使用的参数标识符，必须与声明中的标识符完全一致。

[规则 M8-4-4] 函数标识符要么用于调用函数，要么必须在其前添加 `&` 运算符。

[规则 M8-5-2] 数组和结构体的非零初始化，必须使用大括号来标识和匹配结构。

----

## 类

[规则 A9-3-1] 成员函数不得返回指向类所拥有的私有或受保护数据的非 `const` 原始指针或引用。

[规则 A9-5-1] 不得使用联合体 `Union`。

[规则 A9-6-1] 用于硬件交互或符合通信协议的数据类型，必须是平凡、标准布局类型，且仅包含大小明确的类型成员。

[规则 M9-3-1] `const` 成员函数不得返回指向类数据的非 `const` 指针或引用。

[规则 M9-3-3] 成员函数若能声明为 `static`，必须声明为 `static`；否则若能声明为 `const`，必须声明为 `const`。

[规则 M9-6-4] 有符号整数类型的具名位域，其位宽必须大于 `1`。

----

## 派生类

[规则 A10-1-1] 一个类的非接口类基类不得超过一个。

[规则 A10-2-1] 非虚的公有或受保护成员函数，不得在派生类中重定义。

[规则 A10-3-1] 虚函数声明必须且只能包含以下三个说明符中的一个：(1) `virtual`；(2) `override`；(3) `final`。

[规则 A10-3-2] 每个重写的虚函数都必须使用 `override` 或 `final` 说明符声明。

[规则 A10-3-3] 最终类中不得引入虚函数。

[规则 A10-3-5] 用户自定义的赋值运算符不得为虚函数。

[规则 A10-4-1] 类继承体系应基于接口类构建。

[规则 M10-1-1] 类不应从虚基类派生。

[规则 M10-1-2] 基类仅在钻石型继承体系中使用时，才能声明为虚基类。

[规则 M10-1-3] 可访问的基类，不得在同一继承体系中同时作为虚基类和非虚基类存在。

[规则 M10-2-1] 多继承体系中所有可访问的实体名称必须唯一。

[规则 M10-3-3] 仅当虚函数本身声明为纯虚函数时，才能被纯虚函数重写。

----

## 成员访问控制

[规则 A11-0-1] 非 `POD` 类型应定义为 `class`。

[规则 A11-0-2] 定义为 `struct` 的类型必须满足以下全部要求：(1) 仅提供公有数据成员；(2) 不提供任何特殊成员函数或方法；(3) 不能作为其他结构体或类的基类；(4) 不能从其他结构体或类继承。

[规则 A11-3-1] 不得使用友元声明。

[规则 M11-0-1] 非 `POD` 类类型的成员数据必须为私有。

----

## 特殊成员函数

[规则 A12-0-1] 若类通过 "`=default`"、"`=delete`" 或用户自定义声明，声明了拷贝操作、移动操作或析构函数中的任意一个，则必须同时声明这五个特殊成员函数中的其余所有函数。

[规则 A12-0-2] 不得对对象执行按位操作，以及假设对象内存数据布局的操作。

[规则 A12-1-1] 构造函数必须显式初始化所有虚基类、所有直接非虚基类以及所有非静态数据成员。

[规则 A12-1-2] 同一类型中，不得同时使用非静态数据成员初始化（`NSDMI`）和构造函数中的非静态成员初始化器。

[规则 A12-1-3] 若类的所有用户自定义构造函数，都为数据成员初始化了跨所有构造函数一致的常量值，则必须改用 `NSDMI` 初始化该数据成员。

[规则 A12-1-4] 所有可通过单个基础类型参数调用的构造函数，必须声明为 `explicit`。

[规则 A12-1-5] 类的非常量成员的通用初始化，必须通过委托构造函数实现。

[规则 A12-1-6] 无需额外显式初始化、且需要使用基类所有构造函数的派生类，必须使用继承构造函数。

[规则 A12-4-1] 基类的析构函数必须是公有的虚函数、公有的重写虚函数，或受保护的非虚函数。

[规则 A12-4-2] 若类的公有析构函数为非虚函数，则该类应声明为 `final`。

[规则 A12-6-1] 构造函数初始化的所有类数据成员，必须使用成员初始化器完成初始化。

[规则 A12-7-1] 若用户自定义的特殊成员函数的行为，与编译器隐式定义的特殊成员函数完全一致，则必须使用 "`=default`" 定义，或不进行显式定义。

[规则 A12-8-1] 移动与拷贝构造函数，必须仅对类的基类和数据成员执行对应的移动或拷贝操作，不得产生任何额外副作用。

[规则 A12-8-2] 用户自定义的拷贝与移动赋值运算符，应使用用户自定义的无异常 `swap` 函数实现。

[规则 A12-8-3] 不得对已移动的对象进行读访问。

[规则 A12-8-4] 移动构造函数不得使用拷贝语义初始化其类成员和基类。

[规则 A12-8-5] 拷贝赋值运算符与移动赋值运算符必须能够处理自赋值场景。

[规则 A12-8-6] 基类中的拷贝和移动构造函数、拷贝和移动赋值运算符，必须声明为受保护的，或使用 "`=delete`" 定义。

[规则 A12-8-7] 赋值运算符应使用 `&` 左值引用限定符声明。

[规则 M12-1-1] 不得在构造函数或析构函数体内，使用对象的动态类型。

----

## 重载

[规则 A13-1-2] 用户自定义字面量运算符的自定义后缀，必须以下划线开头，后接一个及以上字母。

[规则 A13-1-3] 用户自定义字面量运算符，只能对传入的参数执行转换操作。

[规则 A13-2-1] 赋值运算符必须返回指向 `this` 的引用。

[规则 A13-2-2] 二元算术运算符和位运算符必须返回纯右值（`prvalue`）。

[规则 A13-2-3] 关系运算符必须返回布尔值。

[规则 A13-3-1] 以转发引用作为参数的函数，不得进行重载。

[规则 A13-5-1] 若重载了非 `const` 版本的 `operator[]`，必须同时实现 `const` 版本。

[规则 A13-5-2] 所有用户自定义转换运算符必须声明为 `explicit`。

[规则 A13-5-3] 不应使用用户自定义转换运算符。

[规则 A13-5-4] 若定义了一对互逆的运算符，其中一个必须基于另一个实现。

[规则 A13-5-5] 比较运算符必须为非成员函数，且具有相同的参数类型与 `noexcept` 说明。

[规则 A13-6-1] 数字分隔符 `'` 仅能在以下场景使用：(1) 十进制数，每 `3` 位数字使用一个；(2) 十六进制数，每 `2` 位数字使用一个；(3) 二进制数，每 `4` 位数字使用一个。

----

## 模板

[规则 A14-1-1] 模板必须对传入的模板实参是否适配该模板进行检查。

[规则 A14-5-1] 模板构造函数不得参与针对所属类类型单个参数的重载决议。

[规则 A14-5-2] 不依赖于模板类参数的类成员，必须在单独的基类中定义。

[规则 A14-5-3] 非成员泛型运算符，只能在不包含类（结构体）类型、枚举类型或联合体类型声明的命名空间中声明。

[规则 A14-7-1] 作为模板实参的类型，必须提供模板所使用的所有成员。

[规则 A14-7-2] 模板特化必须在以下同一文件中声明：(1) 主模板所在文件；(2) 该特化对应的用户自定义类型所在文件。

[规则 A14-8-2] 不得使用函数模板的显式特化。

[规则 M14-5-3] 若类中存在以泛型参数为参数的模板赋值运算符，必须同时声明拷贝赋值运算符。

[规则 M14-6-1] 拥有依赖基类的类模板中，所有可能在该依赖基类中找到的名称，必须通过限定 `id` 或 `this->` 的方式引用。

----

## 异常处理

[规则 A15-0-2] 所有操作必须至少提供异常安全的基本保证。此外，每个函数可选择提供强保证或无异常保证。

[规则 A15-0-3] 必须考虑被调用函数的异常安全保证。

[规则 A15-0-7] 异常处理机制必须保证最坏情况下的执行时间是可确定的。

[规则 A15-1-1] 只应抛出派生自 `std::exception` 的类型实例。

[规则 A15-1-2] 异常对象不得为指针类型。

[规则 A15-1-3] 所有抛出的异常应具备唯一性。

[规则 A15-1-4] 若函数因异常退出，则在抛出异常前，必须将函数内构造的所有对象或资源置于有效状态，或对其进行销毁。

[规则 A15-1-5] 不得跨执行边界抛出异常。

[规则 A15-2-1] 非 `noexcept` 的构造函数，不得在程序启动前被调用。

[规则 A15-2-2] 若构造函数为非 `noexcept`，且无法完成对象初始化，则必须释放该对象的资源并抛出异常。

[规则 A15-3-3] `main` 函数与任务主函数，必须至少捕获以下异常：所使用的所有第三方库的基类异常、`std::exception`，以及其他所有未处理的异常。

[规则 A15-3-4] 全捕获处理（省略号 `...` 与 `std::exception`）仅能在以下场景使用：(a) `main` 函数；(b) 任务主函数；(c) 用于隔离独立组件的函数；(d) 调用使用不符合 `AUTOSAR C++14` 指南的异常的第三方代码时。。

[规则 A15-3-5] 类类型异常必须通过引用或 `const` 引用捕获。

[规则 A15-4-1] 不得使用动态异常说明。

[规则 A15-4-2] 声明为 `noexcept`、`noexcept(true)` 或 `noexcept(<true condition>)` 的函数，不得因异常退出。

[规则 A15-4-3] 函数的 `noexcept` 说明，在所有翻译单元中必须完全一致；对于虚成员函数与其重写函数，重写函数的 noexcept 说明必须与基类一致，或限制更严格。

[规则 A15-4-4] 无异常抛出的函数声明，必须包含 `noexcept` 说明符。

[规则 A15-4-5] 函数可能抛出的受检异常，必须与函数声明一同指定，且在该函数的所有声明及所有重写函数中必须完全一致。

[规则 A15-5-1] 所有用户自定义的类析构函数、内存释放函数、移动构造函数、移动赋值运算符和 swap 函数，不得因异常退出。应根据需要为这些函数添加 `noexcept` 异常说明。

[规则 A15-5-2] 程序不得被异常终止。尤其不得隐式或显式调用 `std::abort()`、`std::quick_exit()`、`std::_Exit()`、`std::terminate()`。

[规则 A15-5-3] 不得隐式调用 `std::terminate()` 函数。

[规则 M15-0-3] 不得使用 `goto` 或 `switch` 语句将控制流转移到 `try` 或 `catch` 代码块内部。

[规则 M15-1-1] `throw` 语句的赋值表达式本身，不得导致异常抛出。

[规则 M15-1-2] 不得显式抛出 `NULL`。

[规则 M15-1-3] 空抛出语句 (`throw;`) 仅能在 `catch` 处理块的复合语句中使用。

[规则 M15-3-1] 仅能在程序启动后、终止前抛出异常。

[规则 M15-3-3] 类构造函数或析构函数的函数 `try` 块实现中，处理程序不得引用该类或其基类的非静态成员。

[规则 M15-3-4] 代码中显式抛出的每个异常，在所有可能触发该异常的调用路径上，都必须有兼容类型的异常处理程序。

[规则 M15-3-6] 同一个 `try-catch` 语句或函数 `try` 块中，若同时提供了派生类及其部分或全部基类的异常处理程序，处理程序必须按派生程度从高到低的顺序排列。

[规则 M15-3-7] 同一个 `try-catch` 语句或函数 `try` 块中提供多个异常处理程序时，任何省略号全捕获处理程序必须放在最后。

----

## 预处理指令

[规则 A16-0-1] 预处理器仅能用于无条件或条件文件包含、头文件保护宏，以及本规范指定的特定指令。

[规则 A16-2-1] 头文件名或 `#include` 指令中，不得出现 `'`、`"`、`/*`、`//`、`\` 字符。

[规则 A16-2-2] 不得存在未使用的 `#include` 指令。

[规则 A16-2-3] 文件中使用的每个符号，都必须显式添加对应的 `#include` 指令。

[规则 A16-6-1] 不得使用 `#error` 指令。

[规则 A16-7-1] 不得使用 `#pragma` 指令。

[规则 M16-0-1] 文件中的 `#include` 指令，之前只能出现其他预处理指令或注释。

[规则 M16-0-2] 宏只能在全局命名空间中进行 `#define` 或 `#undef`。

[规则 M16-0-5] 函数式宏的参数，不得包含看起来像预处理指令的标记。

[规则 M16-0-6] 函数式宏的定义中，每个参数实例都必须用括号包裹（作为 `#` 或 `##` 运算符的操作数时除外）。

[规则 M16-0-7] 未定义的宏标识符，不得在 `#if` 或 `#elif` 预处理指令中使用，作为 `defined` 运算符的操作数时除外。

[规则 M16-0-8] 若 `#` 符号出现在行首，则其后必须紧跟预处理标记。

[规则 M16-1-1] `defined` 预处理运算符只能以两种标准形式之一使用。

[规则 M16-1-2] 所有 `#else`、`#elif` 和 `#endif` 预处理指令，必须与其对应的 `#if` 或 `#ifdef` 指令位于同一文件中。

[规则 M16-2-3] 必须为头文件提供头文件保护宏。

[规则 M16-3-1] 单个宏定义中，`#` 或 `##` 运算符最多只能出现一次。

[规则 M16-3-2] 不应使用 `#` 和 `##` 运算符。

----

## 标准库概述

[规则 A17-0-1] 不得定义、重定义或取消定义 `C++` 标准库中的保留标识符、宏和函数。

[规则 A17-1-1] `C` 标准库的使用必须进行封装与隔离。

[规则 A17-6-1] 不得向标准命名空间中添加非标准实体。

[规则 M17-0-2] 不得重复使用标准库宏和对象的名称。

[规则 M17-0-3] 不得重写标准库函数的名称。

[规则 M17-0-5] 不得使用 `setjmp` 宏和 `longjmp` 函数。

----

## 语言支持库

[规则 A18-0-1] 只能通过 `C++` 库头文件访问 `C` 库功能。

[规则 A18-0-2] 必须检查字符串转数值的转换操作的错误状态。

[规则 A18-0-3] 不得使用 `<clocale>(locale.h)` 库和 `setlocale` 函数。

[规则 A18-1-1] 不得使用 `C` 风格数组。

[规则 A18-1-2] 不得使用 `std::vector<bool>` 特化版本。

[规则 A18-1-3] 不得使用 `std::auto_ptr`。

[规则 A18-1-4] 指向对象数组元素的指针，不得传递给单个对象类型的智能指针。

[规则 A18-1-6] 所有针对用户自定义类型的 `std::hash` 特化，必须拥有 `noexcept` 的函数调用运算符。

[规则 A18-5-1] 不得使用 `malloc`、`calloc`、`realloc` 和 `free` 函数。

[规则 A18-5-2] 不得使用非定位 `new` 或 `delete` 表达式。

[规则 A18-5-3] `delete` 运算符的形式，必须与分配内存时使用的 `new` 运算符形式匹配。

[规则 A18-5-4] 若项目全局定义了带尺寸或无尺寸的 `operator delete` 版本，则必须同时定义带尺寸和无尺寸两个版本。

[规则 A18-5-5] 内存管理函数必须满足以下要求：(a) 行为可确定，具备可预估的最坏执行时间；(b) 避免内存碎片；(c) 避免内存耗尽；(d) 避免分配与释放不匹配；(e) 不依赖于内核的非确定性调用。

[规则 A18-5-7] 若项目中使用了非实时实现的动态内存管理函数，则只能在程序的非实时阶段执行内存分配与释放。

[规则 A18-5-8] 生命周期不超过函数作用域的对象，应使用自动存储期。

[规则 A18-5-9] 动态内存分配与释放函数的自定义实现，必须满足 `C++` 标准中对应 “必需行为” 条款规定的语义要求。

[规则 A18-5-10] 定位 `new` 仅能作用于具备正确内存对齐、且存储空间充足的指针。

[规则 A18-5-11] "`operator new`" 与 "`operator delete`" 必须成对定义。

[规则 A18-9-1] 不得使用 `std::bind`。

[规则 A18-9-2] 向其他函数转发值时，必须遵循以下规则：(1) 若值为右值引用，使用 `std::move`；(2) 若值为转发引用，使用 `std::forward`。

[规则 A18-9-3] 不得对声明为 `const` 或 `const &` 的对象使用 `std::move`。

[规则 A18-9-4] 作为 `std::forward` 实参的变量，在转发后不得再被使用。

[规则 M18-0-3] 不得使用 `<cstdlib>` 库中的 `abort`、`exit`、`getenv` 和 `system` 函数。

[规则 M18-0-4] 不得使用 `<ctime>` 库中的时间处理函数。

[规则 M18-0-5] 不得使用 `<cstring>` 库中的无边界函数。

[规则 M18-2-1] 不得使用 `offsetof` 宏。

[规则 M18-7-1] 不得使用 `<csignal>` 库中的信号处理功能。

----

## 诊断库

[规则 M19-3-1] 不得使用错误指示器 `errno`。

----

## 通用工具库

[规则 A20-8-1] 不得将已被拥有的指针值，存储到无关的智能指针中。

[规则 A20-8-2] 必须使用 `std::unique_ptr` 表达独占所有权。

[规则 A20-8-3] 必须使用 `std::shared_ptr` 表达共享所有权。

[规则 A20-8-4] 无需共享所有权时，必须优先使用 `std::unique_ptr` 而非 `std::shared_ptr`。

[规则 A20-8-5] 必须使用 `std::make_unique` 构造 `std::unique_ptr` 管理的对象。

[规则 A20-8-6] 必须使用 `std::make_shared` 构造 `std::shared_ptr` 管理的对象。

[规则 A20-8-7] 必须使用 `std::weak_ptr` 表达临时的共享所有权。

----

## 字符串库

[规则 A21-8-1] 字符处理函数的参数，必须能表示为 `unsigned char` 类型。

----

## 容器库

[规则 A23-0-1] 迭代器不得隐式转换为 `const_iterator`。

[规则 A23-0-2] 只能通过有效的引用、迭代器和指针访问容器元素。

----

## 算法库

[规则 A25-1-1] 谓词函数对象中，与对象自身标识相关的状态型非静态数据成员或捕获值，不得被拷贝。

[规则 A25-4-1] 关联容器、`STL` 排序及相关算法使用的排序谓词，必须满足严格弱序关系。

----

## 随机数生成

[规则 A26-5-1] 不得使用 `std::rand()` 生成伪随机数。

[规则 A26-5-2] 随机数引擎不得使用默认初始化。

----

## 输入输出库

[规则 A27-0-1] 来自独立组件的输入必须进行校验。

[规则 A27-0-2] `C` 风格字符串必须保证有足够的空间存储数据和空终止符。

[规则 A27-0-3] 文件流上的交替读写操作之间，必须执行刷新或定位操作，否则不得执行。

[规则 A27-0-4] 不得使用 `C` 风格字符串。

[规则 M27-0-1] 不得使用 `<cstdio>` 流输入输出库。

----

**[English Version](./004_AutosarCpp2014规范英文版.md)**

----

