﻿/*
	© 2009-2016 FrankHB.

	This file is part of the YSLib project, and may only be used,
	modified, and distributed under the terms of the YSLib project
	license, LICENSE.TXT.  By continuing to use, modify, or distribute
	this file you indicate that you have read the license and
	understand and accept it fully.
*/

/*!	\file CommonRules.txt
\ingroup Documentation
\brief 公用规则指定和说明。
\version r4474
\author FrankHB <frankhb1989@gmail.com>
\since build 282
\par 创建时间:
	2012-02-03 16:44:56 +0800
\par 修改时间:
	2016-06-03 12:43 +0800
\par 文本编码:
	UTF-8
\par 模块名称:
	Documentation::CommonRules
*/


/*

@0 前言：

@0.1 体例说明：
体例限制为 Unicode(@1.1) 可表示的文本文件，且与其它文档符合 https://bitbucket.org/FrankHB/yslib/wiki/WikiRules.en-US.md 。
（文档专用）外部语义位置标记符：
// 被用作注释。单独一行“//[”表示引用文本段落起始；单独一行“//]”表示引用文本段落终止。
@ //作用于可打印字符或空白符（见以下定义）的字符序列，表示逻辑位置。
以字符串 @@ 起始的字符串作为外部引用章节。
以字符串 @ 起始的字符串本文档内部引用章节。
以字符 @ 起始的行作为章节标题。
同一文件以外的文档引用使用 [] 标注，称为引用标记。
模块名称([Documentation::ProjectRules @@3.2]) 为 Documentation 的引用是本项目的正式文档。本行即为示例。
自然语言为简体中文和英文。

@0.1.1 日期和时间表示：
文本的日期和时间表示基于 ISO 8601:2004(@1.1) 的日期的扩展格式(extended format) 。仅使用精确到日的日期、精确到分或秒的时间，不使用周表示和非完全(complete) 表示。
按 ISO 8601:2004 规定，不在表示内部使用空格。在此约定便于表示解析的例外规则：在表示地方时和 UTC 的差异时使用 ASCII 字符“+”和“-”表示偏差符号，并在此前附加一个空格。

@0.2 使用规则：

@0.2.1 适用范围：
本文档适用于一般开发。

@0.2.2 依赖规则：
在项目中对依赖([Documentation::ProjectRules @@1]) 进行管理。文档引用视为依赖。
除下列例外，本文档不依赖项目内的其它文档：
@0 ；
[Documentation::ProjectRules] 中对项目和文档适用的规则；
对 [Documentation::LanguageConvention] 及 [Documentation::NPL] 中的基本概念定义参考引用（“另见”）。

@0.2.3 来源要求：
[Documentation] 的文档中明确提出需提供文档的描述（如“文档说明”）表示要求至少存在以下文档来源之一：
[Documentation] 中的文档段落；
[Documentation] 中注明“正式引用”一节的文档的段落；
项目源文件中可被 Doxygen 等工具生成文档的源代码片段；
其它另行约定的来源。

@0.3 可读性(readability) ：
一般意义的可读性包含主观因素，即在一定的背景下，特定读者对特定书面文本材料的理解能力可能不同。
为便于规范描述， [Documentation] 中的文档约定忽略主观可读性，由理想情况下的某个读者（参考读者）对不同材料的认识界定使之成为文本材料决定的性质。

@1 绪论：

@1.1 正式引用：
— ISO/IEC 2382 (all parts), Information technology — Vocabulary
— ISO 8601, Data elements and interchangeformats — Information interchange—Representation of dates and times
— ISO/IEC 9899:2011, Programming languages — C
— ISO/IEC 9945:2003, Information Technology — Portable Operating System Interface (POSIX)
— ISO/IEC 10646-1:1993, Information technology — Universal Multiple-Octet Coded Character Set (UCS)
	— Part 1: Architecture and Basic Multilingual Plane
— ISO/IEC 14882:2003, Information technology — Programming languages — C++
— ISO/IEC 14882:2011, Information technology — Programming languages — C++
— ISO 80000-2:2009, Quantities and units — Part 2: Mathematical signs and symbols to be usedin the natural sciences and technology
— The Unicode Standard — Version 6.0 – Core Specification
— GCC Coding Conventions(http://gcc.gnu.org/codingconventions.html)

@1.1.1 引用简写：
ISO C ： ISO/IEC 9899 ；
ISO C++ ： ISO/IEC 14882 ；
ISO C++03 ： ISO/IEC 14882:2003 ；
ISO C++11 ： ISO/IEC 14882:2011 。

@1.2 术语：

@1.2.1 C++ 语言：

@1.2.1.1
以下列表中的概念参考 ISO C++ ：
翻译单元(translation unit) ：(@2/1 [lex])；
字符集(character set) ：(@2.2 [lex.charset])；
预处理记号(preprocessing token) ：(@2.4 [lex.pptoken])；
记号(token) ：(@2.6 [lex.token])；
注释(comment) ：(@2.7 [lex.comment])；
头名(header name) ：(@2.8 [lex.header])；
标识符(identifier) ：(@2.10 [lex.name])；
关键字(keyword) ：(@2.11 [lex.key])；
操作符(operator) ：(@2.11 [lex.operators])；
标点符(punctuator) ：(@2.11 [lex.operators])；
字面量(literal) ：(@2.13 [lex.literals])；
转义[字符]序列(escape sequence) ：(@2.13.2 [lex.ccon])；
实体(entity) ：(@3/3 [basic])；
名称(name) ：(@3/4 [basic])；
作用域(scope) ：(@3.3/1 [basic.scope])；
链接(linkage) ：(@3.5 [basic.link])；
存储期(storage duration) ：(@3.7 [basic.stc])；
类型(type) ：(@3.9 [basic.types])；
对象类型(object type) ：(@3.9 [basic.types])；
不完整类型(incomplete type) ：(@3.9.1 [basic.fundamental])；
命名空间(namespace) ：(@7.3 [basic.namespace]) 。

@1.2.1.2
以下内容参考 ISO C++ 相关描述：
续行/断行连接(line continuation) ：(@2.1/2 [lex.phases])，“splicing physical source lines to form logical source lines”。

@2 设计的基本原理、表达形式和公用抽象：

@2.1 理论背景、工具和依据：

@2.1.1 计算理论和方法学：
离散数学：集合论、组合数学、图论、代数结构、数理逻辑、范畴论……
设计参考的度量理论：可计算理论、计算复杂性理论。
实现参考的度量理论：略。
面向复用的(reuse-oriented) 需求分析和软件设计。
面向对象分析和设计(OOAD) 。
多范型(multiparadigm) 程序设计：过程式(procedual) 程序设计、结构化(structural) 程序设计、面向对象程序设计(OOP) 、面向接口程序设计。

@2.1.2 开发模式：
按需选择合适的开发策略和工程管理方法。
如果可能，保证以上手段的可复用性。

@2.1.3 架构模式(Architectural Patterns) ：

@2.1.3.1 通用抽象设计：
分层(Layers) ；
外观(Facade) ；
调停者(Mediator) ；
管道和过滤器(Pipes and Filters) ；
解释器(Interpreter) 。

@2.1.3.2 交互式设计：
窗体-控件(Form-Control)；
窗口-图标-菜单-指针设备(WIMP, window-icon-menu-pointing device) 。
模型-视图-控制器(Model-View-Controller) /显示-抽象-控制(Presentation-Abstraction-Control) 。

@2.1.3.3 分布式设计：
暂不考虑。

@2.1.4 设计模式(Design Patterns) ：
略。

@2.1.5 解决模式：
错误处理；
任务安排；
数据验证；
同步请求/响应；
……

@2.1.6 实现模式/代码模式/惯用法(Idioms) ：
语言相关。举例： C++ 的 pImpl 、 copy & swap 。

@2.1.7 其它通用设计要点：

@2.1.7.1 语义冗余：
相对目标代码的操作语义，源代码表达可以使用指称方法分析的语义，这些语义（例如名称的语义）中的一部分不可避免地无法通过机器表达，而仅供人类参考。
应控制冗余在适量的程度。

@2.1.7.2 内聚与耦合：
代码的内聚与耦合性质作为评价实现的参照而不是目的。
一般意义下，保持代码的高内聚与低耦合有利于维护。但这个结论并非总是适用于可能发生变化的代码。
在一定的局部范围内，内聚可能是不必要的，耦合也可能是必要的。

@2.1.7.2.1 不必要内聚：
内聚表达模块中子模块之间的关联性相关语义。
内聚需要建立在高度抽象的基础上。
在局部问题域发生变化时，子模块之间的关联可能发生变化。此时，维护内聚性可能会导致不必要的成本。
因此，不必维护所有内聚。

@2.1.7.2.2 必要耦合：
耦合表达模块中子模块之间的依赖性相关语义。
耦合可以用于表示代码的修改需要是事务性的：除非替换所有耦合的局部子模块，否则无法保证代码的质量（正确性和可维护性）不下降。
这增加了合理地修改代码需要的最小工作量，但是，并不一定增加总的工作量。整体替换多个子模块可以更容易地暴露它们之间的冗余，降低优化的工作量。
因此，不必消除所有耦合。

@2.2 模型和构建原则：
基本规则参见 [Documentation::ProjectRules @@3] 。

@2.2.1 人类接口(human interface) ：
本节阐述仅对人类用户有意义，并不直接体现在运行时的原则。

@2.2.1.1 易用性：

@2.2.1.1.1 简单接口：
接口在合理表述语义的基础上应尽可能简单，具有较小的学习成本。

@2.2.1.1.2 最简名称原则：
在接口中使用最少的名称表达合理的语义。
在实现中尽量少引入不必要的名称。即使是为了适应翻译程序（编译器）的功能限制而不得不引入额外的名称，也需要使用有意义的构词，或者至少给出明确的注释。

@2.2.1.2 明确性：

@2.2.1.2.1 否决(deprecation) 控制：
在正式版本释出的(released) 接口若需要废除，在之前不少于一个的临接版本需要通过代码或文档（至少之一）提醒库用户接口的变化。
优先使用 ISO C++14 [[deprecated]] 标注。

@2.2.2 环境(environment)、平台(platform) 环境和可移植性(portability) ：
参见 https://bitbucket.org/FrankHB/yslib/wiki/Terminology.zh-CN.md 。

@2.2.2.1 基本术语补充约束：
平台无关是指代码（源代码或目标代码，下同）在任意现代电子计算机系统（硬件和软件平台）上可约定具有一致行为的最大公共实现的特性；
对程序代码，平台中立是指通过一定的软件手段（附加编码、提供附加二进制工具，例如构建虚拟机作为中间平台）实现一致行为的特性。

@2.2.2.2 存储架构：
除非另行约定，程序设计使用的默认存储位于基于字节（ byte ，参见 ISO C 和 ISO C++ ）编址的二进制主存储器，另见 [Documentation::LanguageConvention @@5.7.2.4] 。
字节地址(byte address) 一般是整数，具有连续取值范围，称为地址空间(address space) 。
处理机中的存储器（寄存器、片内 CACHE ）一般对程序不可见，也不直接按字节寻址。除非另行约定，其它存储器使用和主存储器相同的寻址方式，但编址方式可能不同。
除非另行约定，默认目标平台的一字节包括 8 个对外部可编程接口可见的二进制位。
注意字节序(endianness) ：大端(big-endianness) 、小端(little-endianness) 和 PDP 字节序。平台中立的代码应保证行为不依赖特定字节序。

@2.2.3 可维护性和架构设计：
平衡可复用性和运行期效率。
对增加复用性导致代码可读性降低的情况，应提供额外注释表明实现细节。
翻译单元（以下简称单元）是语言提供对实现进行部署的基础单位，应合理拆分。

@2.2.4 目标代码兼容性(object code compatibility) ：
目标代码兼容性指程序不同部分的目标代码共存可实现预期行为。

@2.2.4.1 体系结构兼容性：
新的体系结构可能提供对旧的体系结构的向后兼容。相同的目标代码在相同体系结构上可以实现相同行为。
除非另行约定，或对特定体系结构提供优化实现，不依赖特定体系结构进行编码。
为了保持可移植性，当提供特定体系结构的实现时，同时应提供其它体系结构的替代实现，明确行为差异在可接受范围内，且不作为公开接口被依赖。
另见 [Documentation::LanguageConvention @@2.2] 。

@2.2.4.2 二进制兼容性(binary compatibility) ：
目标代码是二进制时，不同版本之间的目标代码不一定保证兼容。
对二进制复用的程序组件如库，应指定二进制兼容策略以便于使用和部署。
注意外部依赖项，如使用的库或语言实现可能对此造成影响。
在不同二进制版本之间提供以下的不同强度的保证作为预设策略：
无二进制兼容性：不同版本的替换后需要重新生成二进制代码，否则不保证预期行为。
二进制库向后兼容：新版本的二进制代码可被使用旧版本二进制代码的依赖项使用，保证预期行为，其它同无二进制兼容保证。
库向后兼容：在二进制库向后兼容的基础上，新版本的源码库生成的二进制代码支持被旧版本库的依赖项使用，保证预期行为。
双向兼容：在库向后兼容的基础上，依赖旧版本库的二进制代码可保证被新版本使用。
另见 [Documentation::LanguageConvention @@2.1] 。

@2.3 通用语义：
本节讨论和约定对整个程序及其环境通用的描述和一般性结论，也包括契约和其它约束概念。
关于“对象”在 C++ 语言中的概念，参见 ISO C++ Clause 3 。以此为基础推广的意义参见 @2.3.3.3 。

@2.3.1 可编程性和兼容性：
可编程性是程序表达语义的基础。对通用程序设计，可编程性受到底层实现（例如硬件驱动程序）的约束，仅能够使用有限的接口。
二进制层次上的可编程性在表达语义上无法摆脱底层实现的影响，不利于平台中立的实现，除非有明确说明，不考虑此要求。

@2.3.2 程序模型：
程序模型是具体实现了的架构模式这一结果上进一步抽象的产物，主要从计算机（而不是人类）的角度体现语义表达的一般流程。
在可编程性足够强时，除了实现本身的质量，程序模型几乎只受计算机系统软件（例如语言和操作系统）接口及其实现的约束。
本文档在系统软件领域约定使用以下定义：
程序：有限的指令或其它操作语义方法直接能够表示的内容的集合；
资源：可供计算机系统利用以完成语义表达的实体或信息，可以是硬件或软件；
执行：计算机系统利用资源，使用程序片段实现语义表达的过程；
任务：计算机系统执行特定程序的特定目的。
进程：执行中的程序（一般被作为操作系统调度任务的基本单位）；
线程：进程内部不独占特定资源的最小可执行的调度单位（一般对应程序设计语言逻辑上的控制流）。

@2.3.2.1 运行时程序模型：
由具体项目定义。

@2.3.2.2 资源分类：
（软件）资源分为（软件）系统资源和应用程序资源。
程序本身是系统资源。
作为任务调度单位的进程和线程是系统资源。
处理器资源是硬件资源，由于并不直接出现在源代码中，不是软件资源，不是系统资源；但若实现环境提供直接接口对其进行操作（例如统计 CPU 利用率）时，视作系统资源。
内存储器是硬件资源，经过语言抽象后转换为地址空间。基于实现的原因，地址空间中某些特定的部分最常被利用，如调用栈上的栈帧。这些资源统称为内存资源。内存资源是系统资源。
外存储器是硬件资源，经过实现环境抽象后以文件系统等形式存在，通过应用程序接口等被进程利用。这些形式中的实体（例如文件）在进程中被映射为特定的数据（例如句柄或描述符），这些资源是软件资源，称为外存资源。外存资源是系统资源。
所有被用于直接维持程序调度相关的资源都是系统资源（例如互斥锁）。
其它资源都是应用程序资源。
和内容相关的应用程序资源称为内容资源，包括文本和二进制资源。
二进制资源按内容使用的形式可以分为程序（此处仅指静态的代码集合）、图形、图像、音频、视频等，也包括其它用户自定义格式的数据。

@2.3.2.3 资源管理：
在特定的时间点或控制流中向进程分配和回收具体的资源实例的行为总称为资源管理。资源管理由进程自身在被执行时实现，其逻辑则由程序员在编译期通过源代码对资源的获取和释放操作条件的描述指定。
资源从使用开始到结束的时间段可以认为是连续的，这和对象有相似之处。
利用 RAII（Resource Acquisition Is Initialization ，资源获取即初始化）惯用法可以把特定的对象和资源实例绑定，此时资源的获取和释放与对象的构造和销毁等价，对象的生存期称为资源的生存期。
对 C++ 这样支持确定性析构的语言， RAII 直接使 RRID（Resource Reclamation Is Destruction ，资源回收即析构） 或 DIRR（Destruction Is Resource Reclamation ，析构即资源回收）成为可能。这在异常安全(@5.10.5.1) 等方面有重要意义。
从特定已知来源获取资源的过程为分配(allocation) ，释放资源为去配(deallocation) 。

@2.3.3 实体(entity) 、生存期(lifetime) 和对象(object) ：

@2.3.3.1 实体：
实体是不加限定的语言的抽象。但一般地，需要能明确两个实体是否同一(identical) 。
关于实体，另见 [Documentation::NPL @@ 2.1.1] 。

@2.3.3.2 生存期：
生存期是逻辑上可用的连续区间的抽象，可以在此之上明确特定逻辑事件的顺序，可用抽象的时刻度量。
关于生存期，另见 [Documentation::NPL @@ 4.1] 。

@2.3.3.3 对象：
某些实体具有能明确顺序且可知开端和终结的生存期，这些实体称为对象。
对象表示状态的集合，占用（抽象机意义的，如@5.1.1 ）存储。
关于对象，另见 [Documentation::NPL @@ 4.1] 。

@2.3.3.4 对象的创建(creation) 和销毁(destroy) ：
对象通过创建引入，通过销毁移除。
对象创建完成时生存期开始，销毁开始时生存期终止。

@2.3.3.5 子对象(subobject) ：
特定状态集合作为一个对象的子集，称为这个对象的子对象。
子对象的生存期是所在对象的子集。

@2.3.3.6 实体的复制(copying) ：
实体的复制是以从一个实体为原型(prototype) 引入满足特定比较条件的实体的过程。
复制对象即创建另一个不同的实体。
通常被复制的实体和原型具有某种可被确定的等价关系。
对象的这种等价关系可能是存储的值的相等，即按值复制，符合一般按值调用(call by value) 的函数的语言中的参数传递的典型语义。

@2.3.4 实体所有权(ownership) ：
实体所有权 o 是实体的有限集合 E 上的严格偏序关系(strict partial order) o : E → E，简称所有权。
具有所有权的实体集合称为所有者实体集合（以下简称所有者，记作 O ），另一方称为被托管实体集合（以下记作 P ），需满足：
O ⊂ E ， P ⊂ E ， O ∩ P = Ø 。
因为 o 是严格偏序的，满足反自反、反对称和传递性，它的关系图是有向无环图，称为所有权图。

@2.3.4.1 约定：
当 card(O) = 1 或 card(P) = 1 时，约定可使用其中的唯一元素指代集合本身。
满足 P = Ø 的所有权是空所有权。以下除非另行约定，则“所有权”均指非空所有权。

@2.3.4.2 所有权转移：
所有者的一个所有权被移除，同时另一个实体获得此所有权而成为对应的所有者的过程称为对对应的 P 的所有权的转移。

@2.3.4.3 所有语义和可用性：
所有者负责实现所有语义，即被托管实体的可用性（连续的有效性）的控制。其中最基本的是，实现自身被销毁(destroyed) 时，先行实现对应的 P 的清理(disposition) ，以避免资源泄漏或重复释放。
语言规则可以约定所有权规则。未被任何语言规则保证被托管的实体称为泄漏(leak) ，无法通过语言被访问。泄漏是一种的错误，应避免任意形式的泄漏。

@2.3.4.4 对象所有权和生存期约束：
当实体的所有权中所有者实体和被托管实体都可能是对象。
当两者都是对象时，所有者对象的生存期不晚于被托管对象的生存期开始，不早于被托管对象的生存期结束。
对象对其子对象具有所有权。

@2.3.4.5 实现性质：
由语言特性直接支持，无需显式实现的所有权，称为自动的(automatic) ；除此之外的所有权，称为显式的(explicit) 。
按某些语言的典型语义，一个对象对其子对象（如成员子对象、基类子对象和数组元素）拥有所有权；生存期由语言实现管理的实体由语言的运行时托管。
这些所有权称为平凡的。平凡的所有权是自动的。
非平凡的且的自动的所有权通过语言提供的作用域机制（附带自动生存期）实现。

@2.3.4.6 独占性：
独占所有权是 O 到 E 上的多值函数，即所有权是一对一或一对多的： O 的所有权是排他的，任意 P 的元素有且仅有一个所有者；但 O 的元素可具有 P 中的多个元素的所有权。
共享所有权是非独占所有权。引用计数对象是典型的实例。
一对一的所有权关系称为基本的。平凡的所有权是基本的。
除非另行约定，以下仅讨论非平凡所有权，即被托管实体作为对象通过添加对象引用(@2.3.6) 的方式产生的所有关系中的所有权。

@2.3.4.7 条件所有权：
释放资源前需要进行判断的所有权称为条件所有权，用于实现非特定实体之间（如基于引用计数的智能指针和被引用对象）的所有权。

@2.3.4.8 行为限制：
一旦向实体所有者添加了实体，就不应在从所有者移除此实体前通过所有者以外的途径访问此实体（作用于被托管实体，从所有者实体的元素移除元素的操作除外）。
对 C++ ，由于所有权最终会导致对象被所有者释放，因此具有栈语义的自动对象不宜被添加所有权，否则容易被误释放超过一次。若自动对象被添加所有权，则应确保所有者释放此对象之前，手动从所有者移除此对象。

@2.3.4.9 所有语义和对象释放：
所有语义并不直接体现为操作，而是通过实现中预先定义的策略影响释放行为体现。
对象的所有权关系解除时应保证被托管的对象被清理，保证其生存期终止，以免泄漏。一般可以针对特定所有权关系实现特定的释放器或者删除器(deleter) （可以捆绑在所有者的实现中），在释放时执行具体的操作。
通常默认的释放操作是删除(deletion) ，即通过使被托管对象被销毁，其生存期结束确保所有者对此对象的所有权无效（不可用）。

@2.3.4.10 C++ 实现：
所有权关系可以通过自定义指针等任意具有引用语义的对象实现。
可以通过不可共享的（例如 private ） std::unique_ptr 的实例等具有复制构造时所有权转移语义的对象进行简单实现。
所有者可以是多个对象（如引用计数等涉及多对象公共状态策略的智能指针），但通常被托管的对象组只含有一个对象。
对含有超过一个被托管的对象的所有权关系，可以分解为多个所有权关系以简化实现。

@2.3.5 可选值(optinal value) ：
一类对象可以和特定的可选的值关联，作为特定的默认选项或异常状态。
可选值和其它所有非可选值值可通过特定的比较操作区分。

@2.3.5.1 空值(null value) 和可空(nullable) ：
唯一的可选的值可定义为表示特定的状态不存在的空值。
可具有空值的实体是可空的。
特定的可空类型可以增加特定的附加限制和语义。

@2.3.5.2 可选类型(option type/maybe type) ：
可选类型是对接受一个类型参数的参数化多态类型。

@2.3.6 对象引用和引用关系：
对象的存储可以通过直接引用对象自身访问。
除此之外，可以通过一些特殊的实体引用存储，可以是其它完整对象的存储，也可能是未初始化的。
运行期程序资源实例抽象为对象，可以通过其它的实体的使用进行表示。
被直接访问的实体的称为引用实体，被用于表示资源的对象（集合）称为被引用对象（集合）。
两者作为实体，构成一个反自反、非对称、传递的二元关系，称为引用关系。
为了便于清晰的资源管理，合理的引用关系应为所有权(@2.3.4) 的逆关系，此时不会有循环引用。
除非另行约定，以下的引用关系排除传递性，即多次复合引用关系构成的间接引用，而只考虑直接引用。

@2.3.6.1 决定性：
被引用的资源也可以不是运行期决定的程序资源实例，例如静态类型语言中的函数或类的成员。
资源的引用关系可能在运行时改变。

@2.3.6.2 源和目标：
一个引用关系中，引用实体是被引用对象的引用源，简称源；被引用资源是引用实体的引用目标，简称目标；源指向目标。
目标通常只有一个元素。以下讨论主要涉及此情况，结论对多个资源实例的情况仍然适用。
@2.3.7 分别讨论几类典型的引用源及其实例。

@2.3.6.3 有效性：
引用关系的有效性依赖源和目标的确定存在，一旦无法确定双方即无效。
源可能不保持引用状态，无法通过良好定义的操作确定被引用的对象，此时的源称为无效的，如 @2.3.6.11 。
有效的源和无效的源之间可能通过若干良好定义的操作（如遍历操作， @2.3.6.12 ）互相转换。

@2.3.6.4 存储：
对象具有存储，因此资源和存储之间存在一一映射。此时，对象之间的所有权关系即表示对象与资源、资源与资源之间的所有权关系。
引用实体作为对象时，自身也可以具有存储。
关于引用对象在引用存储时可对目标进行附加操作，参见 @2.3.6 中的以下节。

@2.3.6.5 所有权：
若一个源对目标存在独占所有权(@2.3.4.6) ，则源对此资源是独占强引用的。
若一个源和其它源整体对目标存在共享所有权(@2.3.4.6) ，则源对此资源是共享强引用的。
独占强引用和共享强引用统称强引用。
任何非强引用的源或引用关系是弱引用的。弱引用说明源完全没有对目标的所有权。

@2.3.6.5.1 所有权正规化(normalization) ：
注意所有权是严格偏序的，应保证实体集的并得到的所有权关系图没有环，即禁止出现循环引用。在这个过程中弱引用可用于取代直接对所有权取并集造成循环引用的强引用，称为所有权正规化。

@2.3.6.6 透明性和约束：
若能通过一个源直接得到使用语言特性（如 C++ 引用类型以及内建指针类型的内建 * 操作）对目标的访问，则源对此目标及引用关系是透明的。
任何非透明的源或引用关系是不透明的。
引用关系可以具有修饰符约束，仅公开可对进行操作的部分接口。如 const 约束目标不能通过对源的访问进行修改操作。此时引用关系是不完全透明的。

@2.3.6.7 复制：
引用实体可具有复制(@2.3.3.6) 操作。
引用实体的复制的行为可能有以下的常见策略：
深复制(deep copy) ：导致目标的复制且被复制的源具有目标副本的所有权。对引用对象即按值复制(@2.3.3.6) 。
浅复制(shallow copy) ：目标不因此被复制，保证被复制的源和原有的源指向相同的目标但不具有所有权。
共享复制：在目标复制和指向上同浅复制，但被复制的源和原有的源共享所有权。

@2.3.6.8 转移(moving) ：
引用实体可能具有转移操作。转移操作应不影响目标的生存期和有效性。
引用实体的转移的行为可能有以下的常见策略：
无所有权转移：同浅复制(@2.3.6.7) 。
所有权转移(@2.3.4.1) ：具有强引用的带状态的源（引用对象）在转移操作后放弃所有权，被复制的源指向的原有的源并具有原有的源的所有权。
转移所有权后的引用对象通常具有特定的无效(@2.3.6.3) 状态（如具有空值，参见 @2.3.6.14 ）以和具有所有权的引用对象明确区分。

@2.3.6.9 状态变更：
源可以通过改变自身状态（值）而改变引用关系，例如对源进行赋值操作。
引用实体的所有权转移操作(@2.3.6.8) 是状态变更。

@2.3.6.10 可比较性：
不同的源之间可以定义若干种二元关系运算进行比较。典型的有等价关系（ == ）和偏序关系（ < ）。
源一般是可以比较的。使用等价关系以及非等价（ != ）关系可以判断所给的两个源是否具有相同的可见行为。

@2.3.6.11 间接(indirection) 操作：
间接操作获取具体的唯一目标（通常不直接产生目标的复制；例如始终返回 C++ 内置引用类型或者代理对象），又称解引用操作（ * ）。
当返回 C++ 内置引用或能直接公开目标的操作的类型时是透明的。
可被解引用的源称为可解引用的(dereferenceable) ，这扩展了 ISO C++03 24.1/5 关于迭代器可解引用的定义。
不可解引用的源是无效的。

@2.3.6.12 遍历(traverse) 操作：
改变指向目标的行为的总称。通常至少应包括前向遍历操作（ ++ ）。
源的遍历操作有可能引起无效。

@2.3.6.13 可迭代性：
使源的引用目标在明确的引用目标集合内改变（由间接操作判定，可以确定在迭代后所给的源指向的具体的目标）的操作，称为对源的引用迭代，简称迭代。
一个源当且仅当遍历操作的结果能保证可解引用(@2.3.6.11) 时可有效迭代。
若一个源在经过有限次特定的良好定义的操作（称为迭代操作）后可有效迭代，则此源或引用关系是可迭代的。
任何非可迭代的源或引用关系是不可迭代的。
对可比较相等（ == ）的两个可迭代的源，若其中之一经过有限次迭代操作后比较相等为真，则后者对前者是可达的(reachable) 。
迭代器实例作为引用对象可能确定有效性(@2.3.6.3)，它的目标可以视为一个序列(sequence) 。
若确定迭代器对象不和任何序列关联，则迭代器是奇异的(singular) 。可能奇异的迭代器对象是无效的(@2.3.6.3) 。

@2.3.6.14 可空引用：
对引用对象，扩展 @2.3.5.1 的定义，满足本节以下条件时称为可空的（另见 ISO C++11 NullablePointer 要求）：
可比较相等(@2.3.6.10) ；
可判断有效性(@2.3.6.3) ；
可复制(@2.3.6.7) ；
生存期结束时控制流不中断（析构函数不抛出异常）；
引用指定一个确定的无效状态，具有空所有权(@2.3.4.1) ，此时具有唯一的空值。
默认初始化的引用一般具有空值，也可能具有其它未指定的值。

@2.3.7 一般引用源：
关于引用源参见 @2.3.6.2 。
注意一个引用源可以符合以下多种类别。
为了简便起见，实现可能直接按特定类别使用不满足限定条件的引用实例，如使用不满足不透明性的引用对象作为句柄(@2.3.7.5) 。此时不应该依赖使用受限的操作。

@2.3.7.1 迭代器(iterator) ：
关于“迭代器”的概念，参见 ISO C++ Clause 24 。
迭代器的引用目标是对象（集合，下同）。
迭代器是可迭代(@2.3.6.13) 的。
迭代器一般是弱引用(@2.3.6.5) 的、可浅复制(@2.3.6.7) 的和透明(@2.3.6.6) 的。

@2.3.7.2 指针(pointer) ：
指针是取值为确定有限集的可空(@2.3.6.14) 的引用对象（另见 ISO C++11 NullablePointer 要求）。
指针可能有空值外的其它无效状态(@2.3.6.13) 。

@2.3.7.3 内建指针(built-in pointer)：
C/C++ 内建指针类型是便于对一般机器存储的抽象(@2.2.2.2) 得到的数据类型，是一般的指针(@2.3.7.2) 的特例和原始含义。
内建指针具有丰富的操作和及严格的限制，若不依赖具体存储或体系结构，不需要直接使用。
void* 类型指针引用目标是不确定类型的对象；除此之外，内建对象指针的引用目标是对象（集合）；函数指针的引用目标是非成员或静态成员函数；成员指针的引用目标是非静态成员。
内建指针是语言实现通过地址空间模型实现的引用源，其中对象指针支持算术和关系运算。几乎在所有语言实现中都可以认为是所有引用对象中效率最高的。
内建指针是弱引用(@2.3.6.5) 的：内建指针的生存期和引用目标的生存期无关。
内建指针是透明(@2.3.6.6)的 ：通过 operator* 访问被引用对象。
内建指针是可浅复制的(@2.3.6.7) 和可转移的(@2.3.6.8) ，且转移同浅复制。
void* 类型以及对象指针是可迭代的：通过 operator++ 等实现迭代操作，且可以通过算术运算实现随机迭代，因此是一种特殊的随机迭代器。
和其它典型指针不同，内建指针默认初始化具有未决定值(indeterminate value) ，不能直接作为有效指针对象使用。

@2.3.7.4 智能指针(smart pointer) ：
智能指针的引用目标是对象或不确定类型的资源（以 void 类型作为目标类型时）。
直接智能指针：强引用(@2.3.6.5) 且透明(@2.3.6.6) 的。
间接智能指针：弱引用(@2.3.6.5) 且不透明(@2.3.6.6) 的，不能直接访问目标，需要通过转换为透明的直接智能指针等方式，对被引用对象间接地进行访问。
智能指针一般是不可迭代的。但是对目标中存在多个对象（例如目标是包含多个元素的一个数组）时，可以在内部迭代。
除比较操作外，智能指针满足可空(@2.3.6.14) 要求。空状态是智能指针允许的唯一无效状态，此时指针是不可解引用的(@2.3.6.11) 的。
智能指针支持默认构造空指针。智能指针保证被转移后是空的。
智能指针不一定可以比较或进行指针算术运算，但一般存在用来判断有效性的等效成员 operator bool() 和 bool operator!() ，表现的语义同内建指针在相同操作下一致。

@2.3.7.5 句柄(handle) ：
句柄是引用对象，它的引用目标是对象（不一定是被直接管理的资源）。
句柄可以是强引用(@2.3.6.5) 的，例如对资源进行引用计数。
句柄是不透明(@2.3.6.6) 的：它的值不一定被用户程序明确，可以只通过特定的程序接口访问被引用的资源。
句柄是可复制(@2.3.6.7) 的。
句柄是可转移(@2.3.6.8) 的。
句柄是不可迭代(@2.3.6.13) 的。
句柄一般是可空(@2.3.6.14) 的。
不使用间接操作的内建指针是句柄。
句柄可被默认构造，但构造后不一定是空的（例如内建指针）。
注意句柄的复制语义可能不同。一般句柄操作应区分复制和转移以避免不必要的深复制(@2.3.6.7) 。

@2.3.7.6 实例：
标准库容器的各种迭代器都是典型的迭代器。
ISO C++11 标准库的智能指针中， std::unique_ptr 是独占强引用的透明智能指针， std::shared_ptr 是共享强引用的（当引用计数为 1 时退化为独占强引用）透明智能指针， std::weak_ptr 是弱引用的不透明智能指针。
Windows 内核句柄是弱引用的不透明指针 http://blogs.msdn.com/b/oldnewthing/archive/2007/08/29/4620336.aspx ，但内核对象自身提供侵入式引用计数允许通过特定例程复制共享对象的句柄。

@2.3.8 广义容器和容器(container) ：

@2.3.8.1 广义容器：
广义容器是对确定的实体集合具有所有权的实体的抽象。
满足以下要求的对象称为广义容器：
可空(@2.3.5.1) ；
对其它实体（称为容器的元素）具有独占所有权(@2.3.4.6) ；
深复制：导致元素的对应复制且被复制的容器具有元素副本的所有权；
所有权转移(@2.3.4.1) ：在转移操作后放弃元素所有权，被复制的源具有原有的容器元素的所有权。

@2.3.8.2 平凡容器：
仅具有一个元素或保持为空的广义容器是平凡容器。
可空引用(@2.3.6.14) 是元素为对象的平凡容器。

@2.3.8.3 容器：
容器是可以改变元素数量的广义容器。

@2.4 C++ 对象特性和语义抽象：
本节讨论完成非特定功能但在行为和实现方法上具有显著相似点的某几类对象的性质、意义和行为。

@2.4.1 接口类型：
接口类型是特殊的类类型。接口类型是抽象类，不应被实例化。
接口类型中不含状态（成员数据）；有零个、一个或多个抽象实例方法，但不含具体实例方法。
在 C++ 称为接口类(interface class) 惯用法，使用纯虚函数([Documentation::LanguageConvention @@5.13.7.2]) 实现抽象方法，仅含有纯虚函数的类就是接口类，可作为此处的接口类型。
同常见的其它语言（如 Java 和 C# ）通过语言特性直接支持的接口类型不同，此处约定的接口类型有以下需要注意之处：
由于实现问题，需要允许析构函数非虚（否则被 odr-used(@5.1.8) 时需要额外定义）；
允许有静态数据域（无论是否是常量）和静态成员方法：注意 C++ 基类的作用域独立于派生类，不影响实现；
允许声明类型，包括 typedef 名称和类类型：注意在 C++ 中的基类作用域和派生类作用域的独立性，以及嵌套类实例不包含外围类实例指针；
允许声明友元；
允许使用访问权限控制：可以包含非 public 成员；
允许空接口被实例化：为了简化接口模板通过宏的实现；注意在 C++ 中，无法把纯虚析构函数的定义放在类的声明内部。

@2.4.2 容器：
容器是在逻辑上包含零个或更多个其它对象的对象。
C++ 容器是容器实体(@2.3.8.3) 。

@2.4.3 循环迭代器：
经过有限次前置 operator++ 或前置 operator-- 操作，可以得到初始值的迭代器。
理想情况下，通过迭代操作（至少包括前置 operator++ 和前置 operator--）获得的所有临时迭代器状态中，有且仅有一个无效状态。

@2.5 对象通信(object communication) ：
为简化问题，以下讨论默认关于单一程序的运行时映像（进程）内的通信，但实际应用场合可不仅限于本节讨论范围。

@2.5.1 事件(event) ：
事件是一般意义的动作(action) 在程序中的抽象，是一种状态。
通常某种条件被满足时需要产生事件，称为事件的触发。
事件的触发是即时的，包含发生时间和事件内容两个方面的意义。
需要注意，从实现而言，这种即时性是相对的。原因是事件被触发这一动作在实现中需要时间（例如，占用若干个机器的指令周期）。
所以，发生动作时触发事件指紧接动作完成后产生事件在存储器中的映像。例如，“设置控件位置时产生 Move 事件”指紧随试图设置控件位置的后构造 Move 事件的对象（或进入 Move 事件的处理程序等）。这样的行为在逻辑上有确定的顺序。

@2.5.1.1 事件关联对象
特定的事件的触发可能由特定的对象引起，这类对象称为事件的源(source) 或触发器(trigger) 。
特定的对象可能对特定的事件的触发作出响应，这类对象称为事件的目标(destination) 或响应器(responder) 。
源和目标之间的关系可以是一对一的，也可能是一对多的。前者的事件是单播事件，后者的事件是多播事件。
多播事件的源又称为发送者(sender) ，目标又称为订阅者(subscriber) 。
事件可以被保存在某个特定的对象中，此对象称为此事件的所有者。

@2.5.1.2 事件空间：
有限的不同种类的事件的集合称为事件空间。
事件空间中以整数或枚举类型标识可以区分不同种类的事件。

@2.5.1.4 事件调用：
事件被触发后引起的响应过程称为事件调用。

@2.5.1.4 事件回调：
事件回调是间接的事件调用。
事件可以在生成同时调用预先设置对应关系（注册，对多播事件也称为订阅）的事件处理器（事件响应函数），即同步回调；也可以事件发生后延迟调用，即异步回调。
事件处理器可以是对应参数列表的非成员函数或静态成员函数、非静态成员函数和函数对象。
复杂的回调要求事件能够被带有状态地进行传递，此时需要使用带有状态的仿函数。

@2.5.2 简单事件调用：
可以通过把事件本身抽象为具体的类，借用委托（例如函数指针）实现同步回调。

@2.5.3 消息(message) ：
为了传递事件(@2.5.1) 或其它运行时信息，需把其中的事件内容包装至某一可传递的数据结构中。可使用消息机制解决这个问题。
消息（类型）是为了在应用程序进程内部、应用程序进程之间以及应用程序进程和操作系统之间传递数据的一种具体数据结构。它的实例称为消息（Message）。
使用消息传递事件内容，需要包含消息目的指针、主标识和与其语义相关（具体语义可以取决于主标识，也可以由其它指针域的实际类型决定）的其它参数。除此之外，消息类型中的成员是可定制的。
消息对自身各个数据域保持所有权。因此，必要时，指针域可使用带所有权的智能指针。
各个域完全相等的消息是相等的。除此之外，指针域不等但其内容相等的消息也视为相等。

@2.5.3.1 消息空间：
所有能够在一个处理单元（例如线程）在此单元生存期被处理的消息集合称为消息空间。
除临时对象外，任意完全相同的消息在一个消息空间中不应含有超过一个实例。
消息空间的具体实现可以采用队列等抽象数据结构。

@2.5.3.2 消息队列(message queue) ：
作为消息的容器的一种数据结构，可以一定规则的有序地保存和取出消息。
在消息队列中的消息称为队列消息；其它消息称为非队列消息。

@2.5.4 连接(connection) ：
维持两个实体之间通信关系的状态称为连接。被连接的实体称为端(peer) 。

@2.5.4.1 对等和非对等连接：
需要区分连接两端时，连接是非对等的；否则连接是对等的。
非对等连接中主动提供主要的通信功能实现的实体称为服务端(server) ，另一方称为客户端(client) 。
通常这里提供的功能抽象为传送数据，发送数据的实体是服务端，接收数据的实体是客户端。
注意这里的对等性质不一定是固定的。非对等连接在某一个时刻或时间间隔内可以体现为对等的，例如不进行数据通信。服务端和客户端在特定条件下的角色也可以非固定。
保持对等连接的通信模式称为 P2P （端到端， peer-to-peer ） 通信。

@2.5.4.2 连接对象(connection object) ：
用于表示连接的对象(@2.3.3.3) 称为连接对象。连接对象是对保持连接的资源的抽象。
连接对象至少包含于两端之一。包含连接对象的一端自身可即为连接对象。不包含连接对象的一端在连接建立前可能不存在，而在连接对象初始化时被创建。

@2.5.4.3 连接引用(connection reference) ：
连接引用是引用目标(@2.3.6.2) 为连接对象的引用实体(@2.3.6) 。
连接状态的复制不一定表示连接被有效复制，因此有时需要隐藏连接对象的状态，公开接口中使用对连接对象具有所有权(@2.3.6.5) 的连接引用而不是连接对象。

@2.5.4.4 实例：
连接对象广泛存在于数据通信中。
输入/输出流是保持程序和外部实体（如文件）有序传输连续数据的连接对象。其它实例有保持程序和数据库连接的数据库连接对象、保持程序和网络环境连接的网络套接字对象等。
ISO C++ 标准库中使用 FILE* 作为连接引用，而不是直接储存状态的 FILE 对象来表示打开的流。

@3 API 设计和风格概述：
API 的直接用户是程序员。
双关性： API 作为 Application Programing Interface 解释为用于应用程序实现过程中使用的接口；作为 Application Programer Interface 强调使用的用户。
在此保留缩写。

@3.1 基本语义原则：
总体目标：提供合理的抽象。
以下原则普遍地有效约束 API 的语义，以方便用户的使用。

@3.1.1 简单性：
是简单明确的语义的合理表达，使用户能够自然地使用，包括通过组合现有 API 构造衍生接口。

@3.1.2 完备性：
能够完整地实现所有的期望的确定的特性或功能点。

@3.1.3 最小化：
最小接口优先，人本接口作为例程，引导用户使用 API 进行组合。
注意最小接口在确定功能集的前提下和人本接口对比体现意义。

@3.2 基本形式原则：
以下原则约束 API 的形式，避免可用性受用户关于 API 的设计目的的理解的潜在的不利影响。

@3.2.1 直觉化：
尽可能少地依赖用户的特定经验和背景，实现无歧义的语义表达。
不轻易使用和直觉相悖的设计。

@3.2.2 易于记忆：
具有合理的命名和调用风格，使用户容易按照预期目的使用。

@3.2.3 引导易读的代码：
便于编写便于阅读的用户代码。

@3.2.4 相似衍生：
非严格的最小惊讶原则。

@3.3 实现基础：

@3.3.1 API 命名风格：
标识符命名以标识符命名规约(@4) 为基础。
避免命名空间污染，除非是有意耦合的。

@3.3.2 语用规则：
语言使用规则参见 [CommonRules::LanguageConvention] 。
编码风格参见 @5 。

@3.4 C++ 实现的广义的契约式设计：

@3.4.1
由于语言的限制，语句（块）级别仅使用断言约束。
注意运行时的断言表达式不应有影响程序可观察行为的副作用，以保证启用与不启用断言的程序之间逻辑的一致性。

@3.4.2 面向接口：

@3.4.2.1
使用接口类型(@2.4.1) 。

@3.4.2.2
可选虚继承，但考虑到性能，应尽量避免。

@3.4.2.3
合理使用接口回调、泛型以及混合实现。
协调接口和抽象类的使用。

@3.4.2.4
关于类型转换，参见 @5.11.4 。

@3.5 抽象构建方法：

@3.5.1 接口设计风格：
最小接口优先。
合理分离接口与实现，减少不必要的接口耦合，尽量避免实现耦合。
避免可预测的安全边界之外的防御式编程(defensive programing) ，以避免冗余检查隐藏错误及引入不必要的运行时开销，增加维护成本。

@3.5.1.1 保守成员方法：
涉及类的人本接口应独立于类的定义和实现之外，而不作为成员方法，除非有下列例外。

@3.5.1.1.1 例外 1 ：
方法（特别是被超过一次地）在类的实现中使用。

@3.5.1.1.2 例外 2 ：
非显式地由语法（例如继承和覆盖）约束的相关接口集合（特别是作为不同类中的签名类似的成员方法）。这样可以方便（跨类或跨文件的）重构（目标可能是一个模板）。

@3.5.1.1.3 例外 3 ：
非 public 基类。

@3.5.2 合理封装性：
类不是接口封装的唯一单位。（头）文件可以作为更大粒度的封装单位使用。
使用 C++ 的 pImpl 惯用法(@2.1.6) 辅助封装并分离接口与实现(@3.5.1) 。

@3.5.2.1 封装范围限制实例：
对以类实例的整体为客体的操作（如 Activate 方法；注意无参数的 Clear 、 Reset 等方法不在此列），除了和对象生存期相关的行为（例如构造、析构和初始化），在翻译单元及命名空间内而不是类的内部封装。

@3.5.3 基于类的(class-based) 面向对象设计：
使用合适的语言特性限制类外对类成员或基类的访问：
成员的访问权限参见 [Documentation::LanguageConvention @@5.13.5.2] ；
友元参见  [Documentation::LanguageConvention @@5.5.9] 。

@3.5.3.1 类作为封装单位：
按需封装类的继承体系。

@3.5.3.2 有限继承性：
基本规则参见  [Documentation::LanguageConvention @@5.13.A] 。
使用模块类(@2.4.6) 的多重继承提供实现获得高度可复用性。
仅在必要时使用接口实现。

@3.5.3.3 保守多态性：
仅在必要时或可预见的扩展前提下使用虚函数。
尽可能避免虚继承。

@3.5.3.4
除非必要或有可预见的使用场合，使用聚合而不是组合来构建类。

@3.5.3.5
合理地使用类的成员变量保存状态，仅在必要时通过成员函数实现属性。

@3.6 运行时错误处理：

@3.6.1 值语义常规处理：
使用特定的函数返回值（如空指针常量、默认构造的智能指针值或者空的可选值）表示非预期的有效结果。

@3.6.2 异常：
参见 [Documentation::LanguageConvention @@5.10.5] 。

@3.6.3 日志：
输出可选的、可组织的日志文档。

@3.6.4 错误处理设计策略：

@3.6.4.1 避免非自动存储错误状态：
除非兼容性、相似接口设计风格或环境互操作性的需要，避免使用 errno 等依赖非自动存储的机制以避免对可重入性、线程安全性的限制以及阻碍优化。
使用其它替代机制（返回表示错误的返回值或异常）保证错误处理的局域性。
注意避免 throw-expression 的操作数中直接对使用这些机制的变量求值，除非能保证 throw 求值的过程中不改变错误关联的值（ throw 可能分配存储， errno 没有这个保证）。

@3.6.4.2 错误传播(propagation) ：
具体例程调用的错误通常不总是能原地处理，需要被显式或隐式地传递。
能且需要在发生错误处原地处理错误时，不传播错误。

@3.6.4.3 错误中立(neutrality) ：
传播错误时一般不需要总是对错误表达的状态进行修改，可能出现多次传播的情形。此处使用返回值表示错误导致代码冗余和语义噪音，不利于分离正常控制流和错误处理的控制流。
理想情况下，一个不关心具体错误处理的例程的实现应对是否发生错误保持中立，即不需要根据具体错误的不同修改实现。

@3.6.4.4 错误处理接口：
预见能且应当被原地处理（或忽略）的错误，优先使用返回值传递错误的接口。
多次传播错误且需要错误中立的情形，使用异常控制流表示错误控制流，使用异常中立([Documentation::LanguageConvention @@5.10.5.2]) 实现不预期具体错误处理逻辑的错误中立。在 C++ 以外的语言时可以使用其它具有类似性质的特性或接口代替异常机制，如单子(monad) 。
若不能预期大多数情况下符合上述之一的场景，底层例程应适当考虑同时提供错误返回值（如错误码）和使用异常两种风格的接口。

@3.7 模块化设计：
模块是结构性地对程序的划分，可以是指设计时或运行时的。

@3.7.1 原则：
模块应具有适当的封装性。
保证语义正确的同时控制模块之间的依赖性并减少耦合性。
适当使用语言特性和使用规约隔离模块，尽量不依赖实现相关的机制。

@3.7.2 接口规则：
注意模块边界对接口造成的影响。
必要时严格约束交换存储涉及的对象类型满足 trivally copyable(@5.2.2) 。
减少不必要的耦合。

@3.7.3 互操作、扩展接口和外部接口：
必要时使用插件系统减少解除耦合性。

@3.7.3.1 本机语言实现：
仅在必要时使用。
避免不必要的二进制兼容性依赖。

@3.7.3.2 接口规范：
避免仅因扩展需求而全面依赖基于二进制兼容的接口规范，以减小带来不必要的维护成本的风险：
接口污染；
编码复杂；
迁移困难；
平台依赖。
限制使用的范围包括：
公开的特定厂商的规范，如 Microsoft COM/DCOM 、 Mozilla XPCOM 、CATIA CAA 等；
公开的厂商中立的规范，如 CORBA ；
其它基于特定应用类似非公开机制。
合理使用特定语言的 FFI(foreign function interface) 。

@3.7.3.2 语言绑定(language binding) ：
按照具体场景权衡使用语言绑定、原生实现或嵌入语言(@3.8) 。

@3.8 外部语言：
必要时提供当前以外语言的设计和实现。
实现语言时注意平衡性能和可配置性需求。

@3.8.1 嵌入语言(embedded language) ：
必要时使用和当前程序代码混编的嵌入语言。
嵌入语言可以使用宿主语言(host language) 的实现直接提供实现，也可以使用独立翻译。

@3.8.2 独立翻译：
当嵌入语言实现不适合作为解决方案时，可以使用外部的翻译机制。也适用于实现可另外独立使用的非嵌入语言。
实现可包括解释器和附加代码生成机制（如编译器），需注意翻译开销是否合理。

@3.9 魔数(magic number) ：
魔数是人为特定选取的固定值，这里也包括字符串内容等。
除非公开地显式约定，不在公开接口（如默认参数）中使用魔数。
除非另有约定或领域逻辑需要（如 UI 中的固定文本），不在异常处理相关实现以外使用魔数。

@3.10 元编程(metaprograming) ：
C++ 元编程使用特定的语言构造完成编译时计算。
适当使用元编程接口可以节省运行时开销。注意不应使编译开销过分膨胀。
返回类型或编译时确定的值的类类型被作为元函数(metafunction) 。
特征(traits) ，尤其是类型特征(type traits) ，是用于提取特定的编译时信息辅助元编程的一类元函数。
关于成熟的元编程的使用参照 ISO C++11 type traits 和 boost::MPL 。

@3.11 调用安全性：

@3.11.1 基本概念：
可重入(reentrancy) 指允许递归调用同一个例程。 ISO C 和 ISO C++ 对此有所涉及但没有严格定义。
ISO C11 和 ISO C++11 约定了多线程环境、相关的存储模型及值的计算和副作用的相互作用以及数据竞争(data race) 的概念。
POSIX.1 约定了异步信号安全(async-signal safety) ，参见 POSIX.1-2008 B.2.4 。
POSIX.1 约定了线程安全(thread safety) ，参见 POSIX.1-2008 B.2.9 ；另见 参见 POSIX.1-2008 A.4.17 。
POSIX.1 约定了对线程取消的异步取消安全(async-cancel safety) ，参见 POSIX.1-2008 B.2.9 。
另见 https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html 。
注意可重入和线程安全无必然联系。

@3.11.2 一般准则：
中断服务例程应保证可重入性。
信号处理器应保证异步信号安全性。
对单线程实现环境，不对线程安全性另行约定。
访问外部库提供的外部状态（如 ISO C 的 errno 和 Win32 的 ::GetLastError() ）的例程不具有可重入性，不另行约定和指出。约定线程安全时，假定这些访问线程安全。
因为可移植性因素，不依赖线程取消。除了 POSIX.1 的定义，不假定任何例程异步取消安全。

@3.12 组件和过程语义：

@3.12.1 函数对象(function object) ：
函数对象类型(function object type) 是可以作为函数调用语法的第一个操作数的对象类型；参见 ISO C++11 20.8 。
可调用类型(callable type) 是函数对象类型或成员指针类型；可调用对象(callable object) 是具有可调用类型的对象；参见 ISO C++11 20.8.1 。
调用包装类型(call wrapper type) 是保持函数对象并转发后缀表达式的调用的类型；调用包装(call wrapper) 是具有调用包装类型的对象；参见 ISO C++11 20.8.1 。
注意函数对象类型包括函数指针类型。而函子(functor) 不是 ISO C++ 的正式用词，习惯上专指通过实现 operator() （而不是转换至指针）的类类型函数对象。
以上对象和函数等具有 INVOKE(f, t1, t2, ..., tN) 或 INVOKE(f, t1, t2, ..., tN, R) 的统一后缀表达式调用形式； ISO C++ 要求调用包装可转移构造；参见 ISO C++11 20.8.2 。

@3.12.2 谓词(predicate) ：
使用 bool 类型结果的实体称为谓词，包括非成员函数和成员函数及其引用或调用包装，以及类型特征等元函数。
某些上下文中（如 ISO C++ [thread.req.paramname]）返回可转换为 bool 值的可调用对象是谓词。除非另行约定，不使用此定义。

@3.12.3 非静态成员方法分类：
除了 C++ 特殊成员函数外，一般可以根据是否只读访问对类的非静态成员方法分类。
特定的方法专用于非只读地访问类类型的非静态成员，称为存取方法(mutator method) 或简称存取器(mutator) 。
对应的，只读地访问非静态成员的方法称为访问器(accessor) 。
非只读访问的方法统称修改方法(modifier method) 或修改器(modifiers) ，包括存取器。
非只读访问的方法统称观察者(observers) ，包括访问器。

@3.12.4 设置器(setter) 和获取器(gettor) ：
有时访问器和存取器会被混用（都可同时指只读或非只读访问）导致外延不清，因此有必要约定更明确的设置器和获取器。
习惯上存取器的名称以 set 起始，又称为设置器(setter) ；访问器的名称以 get 起始，又称为获取器(getter) 。关于具体命名，参见 @4.1.7.2 。
不严格使用 C++ 的面向对象特性实现面向对象设计，可以把设置器和获取器推广至类的非静态成员函数范畴之外，只要保证 INVOKE 调用形式(@3.12.1) 等价即可，实际语义为：
设置器修改某一个特定对象的特定子对象；
获取器取某一个特定对象的特定子对象的引用或值。
注意返回 bool 类型的获取器是谓词(@3.12.2) 。因此含义清楚时，排除元编程用途的谓词可以专指返回 bool 类型的获取器。

@3.13 库使用：

@3.13.1 依赖策略：
除非必要，尽量使用标准库。例外情况下应该提供充足理由，并对用户自行替换底层接口和实现提供一定的便利性。

@3.13.2 库使用约定：
除非另行约定，库的头文件按 C++ 标准库头的使用约定，参见 ISO C++11 17.6.2.2 。
使用静态库和动态库时之间可能有差异。参照各个库的文档。

@3.13.2.1 头文件唯一性：
除非重复包含不影响语义，否则应使用特定名称的宏以保证头文件不被包含超过一次。
一般使用守护宏(include guard marco) 保护，包含模式如下：

#ifndef 宏名
#define 宏名 非零整数字面量

//被保护的代码，常以 #include 起始。

#endif

不同头文件应使用不同的宏名。
具体宏名由实现定义。一般应使用特定保留前缀（但不应与标准名称冲突，除非实现标准库，参见 [Documentation::LanguageConvention @@5.3.2.2.2] ）。

@3.13.2.2 头文件包含顺序：
和标准库头不同，因为使用非保留标识符，宏可能对包含顺序造成影响。
除非另行约定，库不检查因为用户代码定义和库中的标识符重复的宏名导致的冲突。
库提供的公开头文件可能 #undef 可能造成冲突的非保留标识符。
用户代码应保证不在包含库的公开头文件之前定义造成冲突（包括使用标准库头以外的系统头文件引入的）的宏名。
一般地，标准库头以外的其它头文件若可能库提供的公开头文件造成冲突，应置于库的公开头文件包含之后，否则应在合适位置插入 #undef 指令消除影响。

@4 基于类 C 语言的标识符命名规约(naming convention) ：
标识符的长度应不大于 ISO C++ Annex B 约定的实现支持的标识符包含字符数的最小值 1024 。
以下是默认风格标识符的命名规则和约定。

@4.1 通用指引：

@4.1.1 原则：
接口一致性：相同接口的命名风格应保持一致。
上下文一致性：尽可能保持上下文命名风格的类似性。
推论：在完善的设计中，若在一个代码片段中存在不同风格的代码，则这些代码不属于同一套接口。
注意：需要存在多套接口的情况下，可能会隐藏潜在的接口设计的不完善性。

@4.1.2 适用范围：
基本例外：
类的 private 成员、不在函数原型中出现的函数声明中的形式参数名称、函数中的块作用域（注意不包括属于函数声明作用域的形式参数列表）、函数作用域（仅限标签名称）和未命名命名空间中的名称不受本规约限制。
经过约定的全局名称可不受本规约限制。

@4.1.3 拼写和构词原则：
基于兼容性考虑，不使用基本源字符集（不另行约定时默认视为兼容 US-ASCII ）以外的 Unicode 字符；不使用 Unicode 字符名(universal-character-name) 。
以美式英语作为命名标识符的基本自然语言参考。
使用 ISO C++ 术语拼写。其它术语使用兼容 GCC Coding Conventions 的术语拼写。剩余术语规范见下文。
若不使用以下构词原则或例外，至少应在原始声明处注释。

@4.1.3.1 基本构词原则：

@4.1.3.1.1 缩略词：
一般除了习惯（例如使用 GUI 表示 Graphic User Interface ），不构造新缩略词。

@4.1.3.1.1.1
被缩写词大小写不改变，例如“GUI”缩写后不作“Gui”。

@4.1.3.1.2 非缩略词和一般词组：
词与词之间需有 "_" 分隔符或大小写不同以示区分。除了 @4.1.3.1.3 中的情况外，通常使用后者。
单词的首字母大写，其它字母保持原形式（通常为小写）不变。
多个单词连用，保持首字母大写，省略其中空格。
这里的单词应是自然语言中较广泛使用的单词，若存在多种拼写方法，使用较常见形式，特别是语言标准中已经有定义的概念（如使用“adaptor”而不是“adapter”）。

@4.1.3.1.3 专有名词例外：
对某些专有名词不受以上限制（除了仍然受语言实现字符集限制）。
例如“GB”（“国标”的汉语拼音缩写）。

$4.1.3.1.4 临时性例外：
例如兼容性考虑的类型名可以全部大写。应注释说明。

@4.1.3.2 框架级名称：
对公开的可能具有二进制互操作性（需要有限保证二进制兼容性）的接口名称（符号），无论是类名、模板名或函数名，无论是否是成员，都应使用大写字母起始的名称。
其它名称无此限制，但应避免非框架级名称与之混淆，例如可以使用 C++ 标准库兼容构词方法(@4.1.3.3) 。
（宏名是预处理符号而不是符号，不适合此命名约定。）

@4.1.3.3 非框架级通用名称：
使用以下的兼容 C++ 标准库风格的构词方法。
使用语言支持（如 range-based for 依赖的 begin 和 end ）、标准库或类似标准库命名风格的通用库（如 Boost ）时，除模板形式参数外的对应实体名称的命名使用库的命名风格，以便保持模板内部名称的兼容性和适当的上下文一致性(@4.1.1) 。
注意对某些惯用名称例如“valarray”，视为单词（非专有名词）而不是词组，因此“ValArray”不是“valarray”对应的默认风格名称。由 @4.1.3.1.2 ，只能保持原文，或者使用同义词组按 @4.1.3.1.2 所述方法得到的“ValueArray”代替。

@4.1.3.4 简单非框架级名称：
在不致混淆的情况下，单字母等（可能是在其它情况下的简单前缀）可以直接作为约束变量（哑变量，如循环变量）或形式参数名称（另见 @4.1.7.4 ）。
下划线和数字组合的名称用于特定模式的参数，类似 std::placeholders 中的公开接口的名称。

@4.1.3.5 其它非框架级名称：
无特殊限制。
模板形式参数可与框架级名称约定一致。

@4.1.3.5 前缀命名法：
慎用前缀。

@4.1.3.5.1
不使用小写字母起始的驼峰命名法（ lowerCamelCase 风格），以免和可能使用的习惯匈牙利命名法的名称(@4.1.3.5.3) 混淆。

@4.1.3.5.2
在有限的类型或模板参数命名场合需要使用变形的系统匈牙利命名法，如 @4.3.5.2 。

@4.1.3.5.3
除了类的 public 成员外，对象命名可以使用习惯匈牙利命名法。

@4.1.3.5.4
起始两个大写字母，之后紧接小写字母的类型（此上下文包含参数化类型，下同）标识符，第一个字符会被作为类型前缀。

@4.1.3.5.5
少数特例(@4.3.5.2) 中，出现在类型标识符起始则被视为既定的类型前缀组合。
一般应避免出现起始两个大写字母，之后紧接小写字母的非前缀标识符，以免混淆。

@4.1.4
在同一作用域中可以使用同一名称表示类型和对象。
（此时引用类型名须使用命名空间限定，否则无法正确编译。）

@4.1.5
语义：函数名以谓语动词（不一定是原型）起始。
成员函数名以动词起始，其它成员不使用谓语动词起始，以示区别。

@4.1.5.1
例外：参见 @4.1.3.1.3 ，如 C/C++ 标准库扩展函数。
为保持风格一致，不使用以上命名规约。

@4.1.6 保留标识符：
一般不应被用户程序使用。
由具体项目定义。

@4.1.6.1 语言相关的默认限制和使用：
参见 [Documentation::LanguageConvention @@5.15.1] 的名称限制。
ISO C++ 内建特性相关的名称使用见 [Documentation::LanguageConvention @@5.3.4] 。
其它参见 @4.1 以下小节。

@4.1.6.2 例外：
已经存在的部分保留标识符允许被用户程序合理地使用。
允许使用 ISO C 和 ISO C++ 的预定义宏以检查版本、特性或使用时间等。
允许使用 C/C++ 实现的预定义宏判断使用的实现和版本。
允许使用 SG6 和 C/C++ 实现提供的标识符 __has_include 和 __has_extension 等以检查和提供兼容性。
允许使用 ISO C 库的公开标识符（如 _IONBF 和 ISO C11 库函数的标识符 _Exit ），及对应 ISO C++ 中的名称（如 std::_Exit ）。
C 语言代码在必要时允许使用 ISO C 中以 _ 起始的关键字，但一般应考虑使用 ISO C 提供的对应的宏代替。
在已知需要依赖特定实现时允许使用适用于特定实现的保留标识符。

@4.1.7 惯用命名：
优先使用以下命名。

@4.1.7.1 原语(primitive) ：
动词原型表示的具有合理自然语义的操作，通常对用户程序来说是原子的(atomic) ，不通过任何进一步的接口名称拆分加以解释。
包括以下名称：
Activate ：激活（设置激活状态）。
Clear ：清除（置参数的主要内容为特定状态；一般置为初始状态）。
Close ：关闭（释放资源，取消资源使用状态）。
Copy ：复制（按指定对象构造相等的新对象）。
Deactivate ：取消（取消激活状态）。
Delete ：删除（销毁参数指定的对象）。
Draw ：绘制（光栅化自身或目标对象）。
Flush ：刷新（刷新对象状态，完成刷新后应保持指定目标和自身同步）。
Merge ：合并（按大于一个非特定类型对象的引用或值参数构造包含所有参数值的对象）。
Open ：打开（获得资源，设置资源使用状态）。
Paint ：绘制（按特定条件完成自身或目标对象的各个组成部分的光栅化）。
Print ：打印（以特定方式输出）。
Refresh ：刷新（刷新对象状态，完成刷新后应保持自身和由自身状态决定的目标同步）。
Reset ：复位（置参数的值为默认状态；一般置为初始状态）。
Release ：释放（参数作为对象或对象引用）。
Swap ：交换（参数作为对象或对象引用）。
Update ：更新（完成参数的特定同步操作）。
注意需要配合使用标准库（进行 ADL(@5.3.3.1)）时，使用 swap 代替 Swap 。尽管不使用 ADL ，为保持一致性，成员函数与之对应也使用 swap 而不是 Swap 。
表示清除容器时，使用 clear 而不是 Clear ，以便满足标准库容器要求。

@4.1.7.2 模式(schema) ：
具有一定规则的名称组合方式表达同类含义（作为前缀的通配符表示的字符串包含作为操作名称的非空前缀；操作名称默认为动词原型，可以是原语(@4.1.7.1) ）。
包括以下名称：
*From ：操作名称起始，第一参数指定源的函数。
*Ptr ：指针（类型为内建指针类型或智能指针类型）。
*Ref ：引用（类型为非 const 引用类型，除 *RRef 外为左值引用类型）。
*RRef ：右值引用（类型为非 const 右值引用类型）
*To ：操作名称起始，第一参数指定目标的函数。
Be*With ：* 为操作名称过去分词（被动语态）；按参数完成特定操作达成特定状态。
Get* ： * 不以 Of 结尾，为目标名称；取特定目标的获取器(@3.12.4) ；通常是 const 非静态成员函数或模板。
Get*Of ： 同 Get* ，但通常为非成员函数或模板，第一参数为目标操作对象的 const 引用。
Is* ： * 为目标名称；谓词：计算目标状态，返回类型为 bool 的结果。
Set* ： * 不以 Of 结尾，为目标名称；修改特定目标的设置器(@3.12.4) ；通常是非 const 非静态成员函数或模板。
Set*Of ： 同 Set* ，但通常为非成员函数或模板，第一参数为目标操作对象的非 const 引用。
On* ： * 为描述事件及事件响应目标的名称；事件处理器。
除非另行约定，匹配 Get* 但匹配 *Ref 结尾的类成员名表示的获取器返回类型应为对象类型或 const 对象引用类型。

@4.1.7.3 ISO C++ 标准库惯用命名：
包括以下成员类型名：
size_type ：表示元素数的无符号整数类型；
difference_type ：表示差值的有符号整数类型；
iterator ：迭代器类型；
const_iterator ：只读迭代器类型；
pointer ：指针类型（注意作为删除器的成员类型可影响 std::unique_ptr 的 pointer 成员类型）；
reference ：引用类型。
包括以下成员函数名：
begin ：表示起始迭代器。
end ：表示终止迭代器。
at ：带有越界检查的访问函数，接受一个左值引用类型的参数，越界时抛出异常（如 std::out_of_range ）；参见 ISO C++ [sequence.reqmts] 和 ISO C++ [associative] 。
swap ：交换函数，接受被交换的左值引用类型的参数，返回类型 void ；参见 ISO C++ [swappable.requirements] 。
包括以下命名空间作用域函数或函数模板名：
to_string ：转换为字符串（通常应为 std::string 类型或至少类型名为 string ）表示。
make_* ：返回特定对象的助手函数（模板）。
swap ：交换函数。
包括以下 ISO C++11 成员函数名：
cbegin ：表示起始只读迭代器。
cend ：表示终止只读迭代器。
包括以下 ISO C++11 命名空间作用域函数或函数模板名，参见 ISO C++ [stmt.ranged] ：
begin ：用于 range based for 的起始迭代器。
end ：用于 range based for 的终止迭代器。
包括以下可能用于 ISO C++14 命名空间作用域函数或函数模板名：
cbegin ：用于 range based for 的起始只读迭代器。
cend ：用于 range based for 的终止只读迭代器。

@4.1.7.4 其它惯用命名：
以 i 起始，拉丁字母表顺序的若干连续字母作为迭代用的哑变量；
表示字符的变量，若不强调所属类别使用 c ；强调宽字符使用 wc ；强调 Unicode 字符使用 uc 。

@4.2 宏名：
保留项参见 @4.1.6 。

@4.2.1
默认使用大写字母。用其它标识符构造的宏以及特殊宏除外。

@4.2.2
特殊宏。

@4.2.2.1
实现语言功能，如interface等。

@4.2.2.2
代码生成器：用宏展开为一段声明或定义的代码。

@4.3 类型名：

@4.3.1
定长整型：全局命名空间中的类型，以前缀和字长组合的形式以明确整型所占的空间。前缀 s 表示有符号整数，前缀 u 表示无符号整数。

@4.3.2
通用类型：非全局命名空间中的类型，小写字母，以 "_t" 作为后缀。

@4.3.3
聚集(aggregate) 类型：数组或容器类型，用不少于2个大写字母和后缀 "s" 组成。

@4.3.4
通用模板类：小写字母，词之间以 "_" 分隔。

@4.3.5
保留类型前缀（关于类型前缀，详细参见 @4.1.2.2 和 @2.4 ）：

@4.3.5.1
全局专有模板类前缀 G(Global Generics) 。可和其它前缀共用。

@4.3.5.2 类型特性划分：
部分使用系统匈牙利命名法。以下前缀适用于 struct 和 class 类型。
非类型参数化的类型前缀（即除了 G 以外的前缀）至多使用两个。
类型特性参见 @2.4 。

@4.3.5.2.1
接口（纯虚类）前缀 I(Interface) 。
对应的接口模板前缀 GI 。

@4.3.5.2.2
包含默认实现语义的虚函数的非严格接口（实际为抽象类）在此也作为接口处理。

@4.3.5.2.3
抽象类前缀 A(Abstract) 。
对应的接口模板前缀 GA 。

@4.3.5.2.4
静态类前缀 S(Static) 。

@4.3.5.2.5
模块类前缀 M(Module) 。

@4.3.5.2.6
句柄类前缀 H(Handle) 。

@4.4
标号：同通用模板类(@4.3.4) 。

@4.5 函数名：

@4.5.1 非成员函数：
以命名空间区分，长度不少于2 。

@4.5.2 成员函数：
除 @4.5.1 限制外， public 函数首字母须大写。

@4.5.2.1
"Get" 和 "Set" 起始的类的成员一定是成员函数；不一定为类的访问器，但须符合访问器的一般语义。

@4.5.2.2
一般不使用缩写，除非有特殊含义。

@4.5.2.2.1
"N" 表示索引或总数。

@4.6 具名对象和引用：

@4.6.1
作为公开接口的 const 变量首字母大写，除非是局部（函数体或以下级别）的临时性常量。

@4.6.2
静态 public 成员首字母大写。

@4.6.3
逻辑上包含同质(homogeneous) 元素（典型情况是包含相同类型的对象）的聚集(aggregate) 的变量名具有后缀 "s" 。

@4.6.4 哑(dummy) 变量：
不超过 2 个小写字母组成。

@4.6.5 其它变量：
不限制。一般同标号。

@5 类 C 语言编码风格导引：
仅叙述之前章节未涉及的内容。一般适用于类 C 语言的源代码，但 @5.1 也适用于其它作为可能被自动识别为代码的内容，包括不直接使用自然语言的文档。
源代码外观仅考虑使用等宽字体的水平显示。
原始字面量(raw literal) 的内容不适用本章的限制，按具体需求决定格式；但除非必要，一般仍需遵循 @5.1 的行宽限制。

@5.1 字符、编码和换行：
禁止使用的字符参见 @5.3.1 。
源代码文件的默认编码使用 UTF-8 ，其它情况需要说明，否则视为临时文件。
原则上一般应优先考虑不使用硬回车保持行宽，即尽量允许通过自动换行调节需要的显示行宽以保证分行排版和其它内容分离。
但限于编辑器限制，当前使用硬回车代替。
默认行宽 80 个半角字符。

@5.2 预处理记号：

@5.2.1 解析：
不使用双联符(digraph) 和三联符(trigraph) 。
必要（当实现不支持 C++11 预处理器特性）时使用一个空格表示预处理记号的边界，避免构成双联符或三联符，如 <:: 改为 < :: 。
注意 ISO C++11 当后续字符不为 > 或 : 时对 <:: 解析为 < 和 :: 而不是 <: 和 : ， ISO C++03 没有此规则。

@5.2.2
不使用替代表达的保留字，参见 @5.4.1 。

@5.2.3
不在一元操作符的表达式内部使用多余的空白符；其它含有（预处理记号的）标点的表达式应保证周围有且仅有一个空白符。

@5.2.4 括号：
除了典型的防止被认为错误（如 if 条件中的赋值表达式或不同层次连续嵌套的 if 和 else 子句）避免警告，不使用不改变语义的冗余的小括号或大括号。
注意小括号可避免使用 ADL ([Documentation::LanguageConvention @@5.3.3.1]) 。
alignas 、 alignof 和 sizeof 表达式使用最外层有括号的形式。
注意 decltype 表达式的子表达式的括号的语义。
return 语句使用无最外层括号形式。

@5.2.5 填充空白符：
作为后缀表达式的组成部分或控制语句紧接关键字后的组成部分的 ( 和左边的标识符（包括关键字，如 catch 、 if 、 for 和 while ）之间不插入额外的空白符。
不使用针对标点的后缀空白符。

@5.3 行首空白符：
不依赖水平制表符的显示宽度，除非另行约定其非缩进的特殊用途。
默认水平制表符显式为 4 个半角字符（以等宽字体的空格计，下同）。
区分缩进和对齐。缩进使用水平制表符，对齐使用空格。另见 @5.3.2 。
避免对齐样式依赖制表符和空格的宽度比。
一般不单独使用对齐。
同一层次的缩进统一使用制表符或相同宽度的空格。
在以上规则约束下，以下缩进使用尽可能少的制表符。
其它行内空白符使用参见 @5.6 。一般执行策略参见 @5.8.2 。

@5.3.1 段落缩进：
成对表示边界的 { 和 } ，若除空白符和边界字符外不存在其它字符，使用相同缩进。
命名空间的直接成员不使用缩进。命名空间名称后的 { 和命名空间定义使用相同缩进。
compound-statement 的边界 { 上一行相同的缩进，内部除单独占据 label 行外使用在边界的基础上多一层次的缩进。
try-block 中的 compound-statement 和 handler-seq 的起始使用和关键字 try 相同的缩进。
labeled-statement 中 case 或 default 标签保持和所在的 switch 相同的缩进，其中非标签内容使用在此基础上多一层次的缩进；其它标签不使用缩进。
ctor-initializer 第一行的 : 前使用上一行基础上多一层次的缩进。
function-try-block 在 ctor-initializer 的 : 前的一个制表符之前插入关键字 try 。
单独占一行的 access-specifier (@5.4.7) 使用所在类定义中 class-key 相同的缩进。

@5.3.2 换行后缩进：
换行后若需使用和第一行不同的缩进量，视为悬挂缩进而不是对齐。
lambda-expression 的基础缩进层次同 lambda-introducer 的首个记号（即 [ ）所在的行的缩进层次，块内以此基础相对悬挂缩进；除此之外，非复合语句换行后使用所在的语句第一行基础上多一层的悬挂缩进。
紧接在续行符后的下一个文本行使用缩进，除非断行在字符串字面量内部。
除以上约定外，非预处理代码（如语句、函数或模板形式参数列表、类或类模板定义的成员列表）若需要换行，第二个换行起使用相同的缩进。

@5.4 分行：
本节约定具体规则。一般执行策略参见 @5.8.2 。
关于行宽的一般规则参见 @5.1 。

@5.4.1 断行连接：
标识符的使用应注意（考虑缩进和对齐后）不超过此限制。其它情况下可以使用行尾的续行符 \ 进行断行连接。
除了标识符超过行宽导致必须分行的情形，当续行符之前存在预处理记号时，两者之间至少一个或多个（仅当需对齐时）空格。
必要时可以同时使用字符串字面量和断行连接。

@5.4.2 语句分行：
labeled-statement 中 : 和之前的记号单独占一行。
任意不同语句（包括复合语句和块的第一个子语句）应始于不同行。

@5.4.2.1 例外 1 ：
声明/初始化相同类型的对象。

@5.4.2.2 例外 2 ：
执行顺序无关的多条短语句序列。
另参见 @5.4.3.3 。

@5.4.3 列表分行：
本节约定列表语法（ISO C++ 中 -seq 或 -list 结尾的语法元素），包括语句、函数或模板形式参数列表、类或类模板定义的成员列表、初始化列表等的分行规则，需要满足以上规则及 @5.6 。
为了描述方便，本节视列表组成元素结尾可选或之后紧接的分隔符（如 , ）包含于列表项。
除了较长的列表项或以下另行约定外，优先使用紧缩分行(@5.4.3.2) 。

@5.4.3.1 宽松分行：
每一个列表项独占一行。
非宽松分行的不同列表项可占同一行。可能会造成可读性降低，酌情使用。

@5.4.3.2 紧缩分行：
紧缩分行是以尽量少占用总代码行数的目标的分行策略，是非宽松分行的特殊情况。
枚举、类和类模板的成员声明一般不使用紧缩分行，以避免造成成员注释过于紧凑。
除非一个记号无法在单行内按指定缩进容纳，不使用续行符。否则，若列表项无法被容纳时，在该项之前换行，且保证行尾不是空白符(@5.6) 。

@5.4.3.3 半紧缩分行：
非宽松分行也非紧缩分行的分行方式。可以视为若干组紧缩分行（每一组至少一行）。
一般初始化列表中的基类子对象初始化和成员对象初始化分为两组半紧缩分行。

@5.4.4 语句序列(statement-seq) 转写：
多个连续的语句若没有相对顺序的严格关系，可写成以标点（可能是内建操作符或非操作符） , 分隔的列表；但在 operator, 可能被重载的上下文中除外，以免混淆。
若表达式具有非 void 类型，可以使用函数参数列表和宏进行辅助。此时求值顺序真正地未被限定，可有利于优化。
对使用内建 operator, 的情况，除语法意义上的不同语句可以合并为同一语句这一变化外，仅作为对代码阅读者的提示。

@5.4.5 括号：
括号 { 、 } 、 [ 、] 、 ( 、 ) 标识声明符以上层次的语法（包括领域专门内嵌语言(domain-specific embedded language)）结构（如函数体）时应独立占一行，除了以下例外：
构成空序列时连写（如 {} 表示空函数体）独立占一行，除非表示此处代码未完成（需要继续扩展）；
lambda 表达式中起始的 { 前不换行。
除此之外，列表分行以括号右边优先于括号左边，即左括号在分行后作为末尾的记号。例如函数参数列表或后缀调用表达式太长时，可在 ( 之后而不是之前分行；模板参数列表太长时，可在 < 之后而不是之前分行。
另见 @5.8.1 。

@5.4.6 模板声明：
模板声明中 template 和被声明的模板名称及模板修饰符以外的修饰符不在同一行，该行以 > 结束。
注意 ISO C++11 对模板上下文 >> 解析为独立的两个 > 而不是操作符 >> ， ISO C++03 没有此规则。一般不在连续的 > 之间分行。

@5.4.7 声明：
除非仅作为显式转换使用的类型名临时使用，不使用无法从左到右直接解析的复杂函数声明符，保证函数声明符能拆分成返回类型和非返回类型（包含参数列表）两部分。
函数及函数模板声明中的返回类型和函数修饰符独占一行。
类成员的 access-specifier 和其后的 : 单独占一行。

@5.4.8 一般分行：
列表项和其它语法成分（如表达式）混合分行时，列表内容按语法树层次优先：先以上层成分为单位尝试分行，若失败（超过行宽限制(@5.4.1) ）则最后一个成分递减，递归进行，直至记号超长需要续行。
除明确指定的分行规则外，保持记号连续的前提下尽量使用较少的行；符合其它规则时使最后行保持最短。

@5.5 空行：
本节约定具体规则。一般执行策略参见 @5.8.2 。

@5.5.1
不使用超过 2 行的空行。

@5.5.2 源代码文件：
在 @5.3.1 的基础上，在源代码文件尾留空行；默认为 2 行。
若文件起始内容为授权声明和版本说明等注释内容(@5.7.4) ，建议和之后的其它内容之间空 2 行。

@5.5.3
#include 指令和非预处理指令之间应该保留空行。

@5.5.4 实体声明空行：
在同一个作用域中，除非另行约定，以下实体的声明之间应保留空行：
类、枚举、函数、函数模板和类模板。
除非另行约定，其它实体的声明之间不使用空行，和上述实体之间的声明保持空行。
需要在声明之间空行时，之间含义差别较小、有连贯性需要时空 1 行，否则空 2 行。

@5.5.4.1 例外：
以下和另行约定的例外规则约定不直接使用上述规则判断空行的情形，包括：
类定义内的对基类成员的 using 声明参照被声明的实体在基类时的分类判断是否需要空行；
连续声明类型（如类或枚举）及以此声明符继续声明实体时，可直接在之后声明，不分行也不空行；
同名实体（如重载）或构造函数/构造模板/析构函数之间同属无名实体的函数或函数模板的声明不空行。

@5.5.5 块作用域：
块的内部应该避免空行，除非用于标识声明语句。
除临时用途（如测试）外，块内不使用函数声明，因此空行可有效分隔和标识 using /类型/变量声明和其它代码。
必要时多个声明可以被拆分为若干不连续的部分，之间允许存在其它代码。
除非特殊需要，连续的声明的顺序依次为 using 声明、类型声明和变量声明。
因逻辑原因标识分隔语句块的，应考虑改用（未命名命名空间的、 inline 的）函数 、 lambda 表达式或其它实体形式包装，而不是插入空行进行分隔。另见 @5.8.1 。

@5.6 分词：
除 @5.3 和 @5.4 外，仅使用空格分隔记号。
注释和字面量外的代码中，除了缩进和对齐(@5.3) 需要外，只使用单独的空格表示间隔。
除 @5.6.2 ，一个记号的所有字符应保证在同一行内。
除非使用多声明符的声明符列表，同一行内的声明符或抽象声明符的 * 和 & 都向左和语法元素靠拢，和右边的语法元素保持一个空格。
除字面量内部，空白符不在行尾出现。

@5.6.1 标点：
行的两端除了之前用于缩进的水平制表符和用于对齐的空格外没有多余的空白符。回避双联符或三连符时允许增加必要的一个空格。
除了以下关于 : 的例外，除去行首的可能存在的空白符后，标点 , 、: 和 ; 不在行首（除非此行紧接在预处理指令后）出现，其它操作符不在行尾出现。
除以上规则适用时，一元操作符及 . 和 -> 的标点和操作数记号之间无空白符；其它括号外的操作符的标点和操作数记号之间有空白符。
关于 ( ，另见 @5.2.4 。关于括号，另见 @5.4.5 。

@5.6.1.1 例外：
: 表示基类列表或初值符列表时，除去行首可能存在的空白符后置于行首，以保持语法和语义的一致性（ : 与增加或修改的列表项在逻辑上是连贯的），也便于插入预处理指令。

@5.6.2 例外：
当超过行宽时允许操作符的标点不在同一行内，此时使用续行符保证逻辑上的行的连续性。

@5.7 注释：

@5.7.1
适用单行注释时不使用多行注释。注意断行连接。

@5.7.2
适用多行注释时可以使用单行注释代替，但行数较大时应首选多行注释。
不在单行注释内部使用多余的 / 修饰外观。
不在多行注释内部使用多余的 * 修饰外观。

@5.7.3
使用注释文档化工具管理时应注意格式统一。

@5.7.4
在非临时的源代码文件头部加入授权声明和版本说明。

@5.8 综合编码风格：
默认使用 Allman style 。注意 ISO C 使用 K&R 为主，而 ISO C++ 混合多种风格。
例外：
函数返回类型使用类 BSD KNF/GNU 风格，即第一个非指针声明符（ noptr-declarator ，参见 ISO/IEC 14882 Clause 8 ）后换行。

@5.8.1 复合语句：
在块内部除非必要（析构函数的副作用），不使用冗余的复合语句的边界表示层次。
对只含一个语句的复合语句，除非语法限制（如作为函数体）和以下例外，转换为非复合语句。

@5.8.1.1 例外：
为便于搜索区分， do-while 的循环体边界保留 { 和 } 。
（注意按 @5.2.5 ， } 和 while 之间不保留空白符。）

@5.8.2 一般缩进、分行和空行策略：
对每个预处理翻译单元按以下顺序执行代码格式化算法。
按 @5.5.2 组织文件起始和末尾的空行；
按 @5.5.3 组织预处理之间的空行；
忽略已约定的影响的固定策略的上下文（如标识语句位置或组织语句块的宏的调用，包括其括号），占据单独的行即忽略整行；
按 @5.8.2.1 处理。

@5.8.2.1 翻译单元缩进、分行和空行策略：
对翻译单元内的顶级声明按行首空白符规则(@5.3) 处理；
按 @5.5.4 组织顶级声明之间的空行；
按 @5.8.2.2 处理。

@5.8.2.2 块作用域缩进、分行和空行策略：
按 @5.5.5 在声明、非声明以及断言等可能涉及预处理语法构造之间划分必要的空行；
对上述划分的每个部分按 @5.8.2.3 处理。

@5.8.2.3 语句缩进、分行和空行策略：
若为复合语句，按 @5.8.2.2 递归处理；
按 @5.8.2.4 处理。

@5.8.2.4 非复合语句缩进、分行和空行策略：
试验符合 @5.3 、 @5.4.1 、 @5.4.2 和 @5.6 的规则约束下最紧凑（尽可能少地使用空白符）的代码格式，记录代码行数；
在满足以上规则和结果行数的约束下增加 @5.4 的其余约束，若存在解则算法结束；
否则结果行数增加 1 ，继续验证上述增加 @5.4 的其余约束的解是否存在。
显然不限制结果行数上限时解存在。

@5.9 类成员和类定义内声明规则：
以下为一般建议性规则。若满足 ISO/IEC C++ 或 ISO/IEC C++ TR 内指出的接口要求或参照类似接口，经指出后不使用此顺序。
除非另行约定，关于声明顺序排列的规则的优先级以从高到低排列。

@5.9.1 基本原则：
一致性原则：声明和实现（定义）若分离，顺序应保持一致，以便查找。
类定义内声明顺序规则：分为区段规则和非区段规则，参见 @5.9.2 。
当且仅当公开实现时，在类定义内提供公开函数体的成员函数定义，但成员函数模版因为复杂性可以例外。
仅在必要时使用类名声明。

@5.9.2 声明区段(section) ：
为明确顺序，划分类定义内的声明的组合为若干区段。
同一区段的声明之间连续（即不穿插其它区段的声明），不同区段之间具有明确的顺序。
区段按声明的语法形式归类划分。区段内可以划分子区段（如按限定符）。
根据区段明确的声明顺序规则称为区段顺序规则。非区段顺序规则优先于区段顺序规则。

@5.9.3 非区段顺序规则：
若应用区段顺序规则后导致使用未声明的名称，且可以通过调整声明顺序解决，则允许调整声明顺序。
using 声明（非别名声明）和 static_assert 声明不受区段顺序规则限制。
除了数据成员布局需要，无视访问权限。

@5.9.4 区段顺序一般规则：
同一区段内，非静态成员先于静态成员。

@5.9.5 声明区段划分和特定区段顺序规则：
总体区段以类型/模板类型、数据成员、其它成员或非成员（包括类定义内的友元声明等）顺序排列。

@5.9.5.1 类型/模板类型声明：
一般应该保证非模板优先。

@5.9.5.2 数据成员：
分为两个区段，以静态数据成员、非静态数据成员的顺序排列。

@5.9.5.2.1 静态数据成员
按 cv-qualifier 和 constepxr 分为以下区段，以 constexpr 、 const 、 const volatile 、 无限定 、 volatile的顺序排列。

@5.9.5.3 其它成员或非成员：

@5.9.5.3.1 名称区段：
操作符（以 operator 起始）名称在同一区段其它名称之前；
其它成员或非成员声明按各区段之间的名称在用于满足特定的接口约定（如 ISO C++ 容器要求）时按接口约定排列，否则按字典序排列；
非静态数据成员需要调整布局时可以例外。

@5.9.5.3.2 非成员区段与成员区段：
名称相同的非成员函数与非成员函数模板先于对应类型的成员函数与成员函数模板。

@5.9.5.3.3 重载区段：
构成重载的所有成员声明之间不插入其它成员声明。
对同一个名称的成员，成员重载先于非成员重载。
对仅有参数列表不同的重载函数或重载函数模板，以从左至右的前缀顺序排列。
涉及特殊成员函数的重载以默认构造函数、其它构造函数/构造模板、复制构造函数、转移构造函数、析构函数、其它赋值操作符函数/模板、复制赋值操作符函数、转移复制操作符函数的顺序声明，优先于以下子区段规则。
仅限定符不同或仅修饰相同位置参数中的限定符构成重载的区段：首先按 cv-qualifier 以无限定、const 、volatile 、const volatile 排列，其次按 ref-qualifier 以无限定、 & 、 && 排列；但命名空间作用域中若在接口语义或实现中存在声明（调用）依赖则允许使用其它顺序（但应尽少改变）。
类型和所有的限定符一致的成员函数先于成员函数模板。

@5.9.5.3.4 伪重载区段：
以 const_ 前缀修饰类型名同 @5.9.5.3.3 规则排列，如 iterator 先于 const_iterator 。

@5.9.6 一般具体声明顺序：
以下同一区段内，按约定顺序排列；约定同类顺序的， @5.9.5.3.1 的规则排列；需其它确定顺序时（如依赖实现的第一个 virtual 函数控制包含 vtable 的翻译单元）需要文档说明。
using 声明引用基类的成员时，只考虑（非限定的）成员名，和派生类直接声明的成员之间不作区分。
当需要向前引用名称查找依赖声明顺序的成员（如 using 别名需要静态 constexpr 对象的值）时可以存在尽可能少的例外。
友元类和友元模板；
嵌套类、嵌套类模板；
typedef 或代替 typedef 的 using 别名；
静态 constexpr 数据成员；
静态非 constexpr 的 const 数据成员；
静态无限定数据成员；
静态 volatile 数据成员；
非静态数据成员；
继承构造函数或构造模板；
默认构造函数；
以基类引用参数作为唯一参数的构造函数；
其它（满足 @5.9.5.3.3 前缀顺序规则，排除首个参数与以下提及同类的相同的，下同）构造函数或构造模板；
复制构造函数；
和复制构造函数第一个参数相同的其它构造函数；
（对类模板）和复制构造函数仅有首个函数参数类型的模板参数不同的构造模板；
转移构造函数；
和转移构造函数第一个参数相同的其它构造函数；
（对类模板）和转移构造函数仅有首个函数参数类型的模板参数不同的构造模板；
第一个参数是初值符列表的构造函数；
析构函数；
用于逻辑初始化的 private 静态或非静态成员函数或成员模板；
用于逻辑初始化的 protected 静态或非静态成员函数或成员模板；
替换为包括超过一个特殊成员函数或对应名称的函数模板的成员声明的宏调用；
以基类引用参数作为唯一参数的赋值操作符函数；
以基类引用参数作为唯一参数的赋值操作符模板；
其它简单赋值操作符函数或模板；
复制赋值操作符；
和复制赋值操作符的第一个参数相同的其它赋值操作符；
（对类模板）和复制赋值操作符仅有首个函数参数类型的模板参数不同的简单赋值操作符模板；
转移赋值操作符；
和复制赋值操作符的第一个参数相同的其它转移操作符；
（对类模板）和复制赋值操作符仅有首个函数参数类型的模板参数不同的简单赋值操作符模板；
第一个参数为初值符列表的赋值操作符；
组合赋值操作符（以 += 、 -= 、 *= 、 /= 、 %= 、 <<= 、 >>= 、 &= 、 |= 的顺序）；
一元操作符（以 ! 、 ~ 、 + 、 - 、 & 、 * 的顺序)；
重载 operator-> ；
重载 operator->* ；
自增/自减（以前缀自增、后缀自增、前缀自减、后缀自减的顺序）；
重载 operator[] ；
关系操作符（以 == 、 != 、 < 、 <= 、 > 、 >= 的顺序）；
算术操作符（以 + 、 - 、 * 、 / 、 % ）的顺序；
二元位操作符（以 << 、 >> 、 & 、 | 、 ^ 的顺序）；
逻辑操作符（以 && 、 || ）的顺序；
分配/去配操作符（以 new 、new[] 、 delete 、 delete[] 的顺序）；
转换操作符（以整数类型、枚举类型、其它基本类型、类类型顺序；整数类型之间以转换阶(conversion rank) 从小到大的顺序排列）；
其它函数或函数模板。

@5.10 宏嵌入式领域特定语言(macro embedded domain-specific language) ：
使用 C/C++ 宏实现的领域特定语言若可约定与内建语言类似形式（函数调用等）不同的语义，则可约定以上规则的例外。
宏调用可能被替换为表达式，称为表达式宏。
非表达式宏结束一般不冗余语句结尾的标点（ ; 或 } ）。

*/
////

