﻿/*
	Copyright by FrankHB 2009 - 2013.

	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 r2135
\author FrankHB <frankhb1989@gmail.com>
\since build 282
\par 创建时间:
	2012-02-03 16:44:56 +0800
\par 修改时间:
	2013-04-22 12:37 +0800
\par 文本编码:
	UTF-8
\par 模块名称:
	Documentation::CommonRules
*/


/*

@0 前言：

@0.1 体例说明：
（文档专用）外部语义位置标记符：
@ //作用于可打印字符或空白符（见以下定义）的字符序列，表示逻辑位置。
以字符串 @@ 起始的字符串作为外部引用章节。
以字符串 @ 起始的字符串本文档内部引用章节。
以字符 @ 起始的行作为章节标题。
//E = Experimental;

@0.2 限制：
体例限制为 Unicode(@2.1) 可表示的文本文件。
自然语言为简体中文和英文。
满足以上条件，不限制其它语言使用。

@1 绪论：

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

@1.1 正式引用：
— ISO/IEC 2382 (all parts), Information technology — Vocabulary
— ISO/IEC 9899:1999, Programming languages — C
— ISO/IEC 9899:1999/Cor.3:2007(E), Programming languages — C, Technical Corrigendum 3
— 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/IEC TR 19769:2004, Information technology — Programming languages, their environments and system software interfaces — Extensions for the programming language C to support new character data types
— The Unicode Standard — Version 6.0 – Core Specification

@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.2.1 测试：
默认为部分整体回归测试代替单元测试。

@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 构建原则：

@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 过时(deprecated) 控制：
在正式版本释出的(released) 接口若需要废除，在之前不少于一个的临接版本需要标注 deprecated 提醒库用户接口的变化。

@2.2.2 可移植性相关：

@2.2.2.1 基本术语补充定义：
关于平台无关性（或平台独立性）(platform-independent) 和平台中立性(platform-neutral) ：
一般意义上大致相同，但本文档附加约定：
平台无关性是指代码（源代码或目标代码，下同）在任意现代电子计算机系统（硬件和软件平台）上可以具有一致行为的最大公共实现的特性；
平台中立性是指代码通过一定的软件手段（附加编码、提供附加二进制工具，例如构建虚拟机作为中间平台）实现一致行为的特性。
平台中立性逻辑蕴含平台无关性。平台无关性的条件更严格。

@2.2.2.2 存储架构：
如无附加说明，程序设计使用的默认存储位于基于二进制编址的主存储器。
主存储器寻址的基本单位称为字节(byte) 。一般以整数编址，具有连续取值范围，称为地址空间(address space) 。
处理机中的存储器（寄存器、片内 CACHE ）一般对程序不可见，也不直接按字节寻址。如无附加说明，其它存储器使用和主存储器相同的寻址方式，但编址方式可能不同。
如无附加说明，默认目标平台使用 8 位为一字节。
注意字节序(endianness) ：大端(big-endianness) 、小端(little-endianness) 和 PDP 字节序。平台中立的代码应保证行为不依赖特定字节序。

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

@2.3 通用语义：
本节讨论和约定对于整个程序及其环境通用的描述和一般性结论，也包括契约和其它约束概念。
关于“对象”的概念，参见 ISO C++ Clause 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 ，析构即资源回收）成为可能。这在异常安全(@3.6.2.1) 等方面有重要意义。

@2.3.3 对象所有权：

@2.3.3.1 概述：
对象所有权是对象组（对象的集合）之间的二元关系，简称所有权。
具有所有权的对象组称为所有者对象组（以下简称所有者，记作 O ），另一方称为被托管对象组（以下记作 P ），且满足 O 和 P 的交集为空集。
当 card(O) 或 card(P) 等于 1 时，约定可以使用其中的唯一元素指代集合本身。
 P 是空集的所有权是空所有权。以下若不另外注明，则“所有权”均指非空所有权。
所有权是一对一或一对多的：所有者拥有的所有权是排他的，即任意被托管对象有且仅有一个所有者（集合）；但反之一个所有者可以拥有超过一个被托管对象组的所有权。
所有者的一个所有权被移除，同时另一个对象组获得此所有权而成为对应的所有者的原子过程(atomic procedure) 称为对对应的 P 的所有权的转移。
所有者负责实现所有语义，即被托管对象的可用性（连续的有效性）的控制。其中最基本的是，实现自身被销毁(destroyed) 时，先行实现对应的 P 的释放(disposition) ，以避免资源泄漏或重复释放。

@2.3.3.2 分类：
由语言特性直接支持，无需显式实现的所有权，称为自动的 (automatic) ；除此之外的所有权，称为显式的 (explicit) 。
根据语言实现的类成员和继承特性对应的语义，一个对象对成员对象和子对象拥有所有权。这些所有权称为平凡的。平凡的所有权是自动的。
非平凡的且的自动的所有权通过语言提供的作用域机制（附带栈语义）实现。
如无说明，以下仅讨论非平凡所有权，即被托管对象组通过添加对象的指针（包括智能指针等实现引用语义的对象）的方式产生的所有关系中的所有权。
一对一的所有权关系称为基本的。平凡的所有权是基本的。
一对多的所有权关系称为共享的。引用计数对象是典型的实例。
释放资源前需要进行判断的所有权称为条件所有权，用于实现非特定对象之间（如基于引用计数的智能指针和被引用对象）的所有权。

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

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

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

@2.3.4 存储和其它资源引用：
对象的存储可以通过直接引用对象自身访问。
除此之外，可以通过一些特殊的对象引用存储，可以是其它完整对象的存储，也可能是未初始化的。

@2.3.4.1 对象引用关系：
运行期程序资源实例可以通过对象的使用进行表示，构成一个引用关系。被直接访问的对象称为引用对象，被用于表示资源的对象（集合）称为被引用对象（集合）。

@2.3.4.1.1 类型限制：
被引用的资源也可以不是运行期程序资源实例，例如静态类型的函数或成员。

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

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

@2.3.3.1.4 引用和存储：
对象具有存储，因此资源和存储之间存在一一映射。此时，对象之间的所有权关系即表示对象与资源、资源与资源之间的所有权关系。
关于引用对象在引用存储时可以对被引用的对象进行附加操作，参见 @2.3.3 。

@2.3.3.1.5 引用和所有权：
若一个源对目标存在一对多或一对一的所有权，则源对此资源是完全强引用的。
若一个源对目标存在多对多或多对一的所有权，则源对此资源是不完全强引用的。
完全强引用和不完全强引用统称强引用。
任何非强引用的源或引用关系是弱引用的。弱引用说明源完全没有对目标的所有权。

@2.3.3.1.6 透明性：
若能通过一个源直接得到使用语言特性（ C++ 引用类型）对目标的访问，则源对此目标是透明的。
任何非透明的源或引用关系是不透明的。

@2.3.3.1.7 约束类型：
引用关系可以具有修饰符约束，如 const 约束目标不能通过对源的访问进行修改操作。

@2.3.3.1.8 状态变更：
源可以通过改变自身状态（值）而改变引用关系，例如对源进行赋值操作。

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

@2.3.3.1.10 间接(indirection) 操作：
间接操作获取具体的唯一目标（一般不是值语义，例如返回内置引用类型），又称解引用操作（ * ）。
可被解引用的源称为可解引用的(dereferenceable) ，这扩展了 ISO C++03 24.1/5 关于迭代器可解引用的定义。
不可解引用的源是无效的。

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

@2.3.3.1.12 可迭代性：
使源的引用目标在明确的引用目标集合内改变（由间接操作判定，可以确定在迭代后所给的源指向的具体的目标）的操作，称为对源的引用迭代，简称迭代。
一个源当且仅当遍历操作的结果能保证可解引用时可有效迭代。
若一个源在经过有限次良好定义的操作后可有效迭代，则此源或引用关系是可迭代的。
任何非可迭代的源或引用关系是不可迭代的。

@2.3.4.2 迭代器(iterator) ：
关于“迭代器”的概念，参见 ISO/IEC 14882 Clause 24 。
迭代器的引用目标是对象（集合，下同）。
迭代器应是弱引用的、透明的和可迭代的。

@2.3.4.3 内建指针(built-in pointer)：
 C/C++ 内建指针类型是便于对一般机器存储的抽象(@2.2.2.2) 得到的数据类型。若不依赖于具体存储，不需要直接使用。
 void* 类型指针引用目标是不确定类型的对象；除此之外，内建对象指针的引用目标是对象（集合）；函数指针的引用目标是非成员或静态成员函数；成员指针的引用目标是非静态成员。
内建指针是语言实现通过地址空间模型实现的引用源，其中对象指针支持算术和关系运算。几乎在所有语言实现中都可以认为是所有引用对象中效率最高的。
内建指针是弱引用的：内建指针的生存期和引用目标的生存期无关。
内建指针是透明的：通过 operator* 访问被引用对象。
 void* 类型以及对象指针是可迭代的：通过 operator++ 等实现迭代操作，且可以通过算术运算实现随机迭代，因此是一种特殊的随机迭代器。

@2.3.4.4 智能指针(smart pointer) ：
智能指针的引用目标是对象或不确定类型的资源（以 void 类型作为目标类型时）。
直接智能指针：强引用且透明的。
间接智能指针：弱引用且不透明的，不能直接访问目标，需要通过转换为透明的直接智能指针等方式，对被引用对象间接地进行访问。
智能指针一般是不可迭代的。但是对于目标中存在多个对象（例如目标是包含多个元素的一个数组）时，可以在内部迭代。
作为指针，智能指针允许为无效状态，此时指针具有空所有权(@2.3.3.1) ，是空的(null) 、不可解引用的(non-dereferenceable) 。
智能指针不一定可以比较或进行指针算术运算，但一般存在用来判断有效性的等效成员 operator bool() 和 bool operator!() ，表现的语义同内建指针在相同操作下一致。

@2.3.4.5 句柄(handle) ：
句柄的引用目标是对象（本身不一定是要被管理的资源）。
句柄可以是强引用的，例如对资源进行引用计数。
句柄一般是不透明的：它的值不一定被用户程序明确，可以只通过特定的程序接口访问被引用的资源。
句柄是不可迭代的。

@2.3.4.6 实例：
标准库容器的各种迭代器都是典型的迭代器。
 ISO C++11 标准库的智能指针中， std::unique_ptr 是完全强引用的透明智能指针， std::shared_ptr 是不完全强引用的透明智能指针， std::weak_ptr 是弱引用的不透明智能指针。

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

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

@2.4.2 容器：
容器是在逻辑上包含零个或更多个其它对象的对象。

@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 连接对象(connect object) ：
用于保持两个实体之间通信关系和状态的对象称为连接对象。
连接对象是对保持连接的资源的抽象。

@2.5.4.1 对等和非对等连接：
当连接两端的实体一端发送、另一端接收数据时，连接是非对等的。发送端称为服务端(server) ，接收端称为客户端(client) 。
除此之外的连接是非对等连接。非对等连接在某一个时刻或时间间隔内可以体现为对等的，或不进行数据通信。
对等连接作为通信模式称为 P2P （端到端， peer-to-peer ） 通信。

@2.5.4.2 实例：
连接对象的实例有保持程序和数据库连接的数据库连接对象、保持程序和网络环境连接的网络套接字对象等。

@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 语用规则：
参见 @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 接口设计风格：
最小接口优先。
合理分离接口与实现，减少不必要的接口耦合，尽量避免实现耦合。

@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) 面向对象设计：

@3.5.3.1 类作为封装单位：
按需封装类的继承体系，尽可能使用 private 成员而不是 protected 成员。
必要时（例如特定操作符重载，或基于操作名称的自然语义考虑）使用友元突破类的封装性限制。

@3.5.3.2 有限继承性：
使用模块类(@2.4.6) 的多重继承提供实现获得高度可复用性。
仅在必要时使用接口实现。
尽可能使用组合代替 private 继承，除非需要使用派生类覆盖 private 基类的（纯）虚函数。

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

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

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

@3.6 运行期错误处理：

@3.6.1 值语义常规处理：
使用特定的函数返回值（如 NULL ）表示非预期的有效结果。

@3.6.2 异常：
仅在必要时使用异常。
除非有必要，不使用嵌套 try 块。

@3.6.2.1 异常安全：

@3.6.2.1.1 最低异常安全性保证：
总是保证最低安全性，避免异常处理造成资源泄露。

@3.6.2.1.2 强异常安全性保证：
必要时实现抛出异常后的状态回滚。

@3.6.2.1.3 无异常抛出保证：
必要时使用，禁止异常导致控制流中断。

@3.6.2.1.4 资源生存期：
优先使用 RAII 和确定性析构的 RRID(@2.3.2.3) 实现异常安全的设计。

@3.6.2.2 异常中立：
除非属于内部实现或异常能够被合适地完全处理，总是向调用者重新抛出捕获的异常。

@3.6.2.3 异常对象：
注意 throw 表达式中的对象需要满足可复制构造。
除非必要，抛出的异常对象应具有类类型，即异常类(@3.6.2.4) 。

@3.6.2.5 异常类：

@3.6.2.5.1 异常类特性：
异常类是空类或多态类。
除非必要（如考虑性能），一般以 std::exception 作为基类。
异常类可使用多重继承。
异常类可使用虚继承。

@3.6.2.5.2 异常类成员：
不包含 std::string 或其它有可能在复制构造时抛出异常的成员。这可能会直接导致程序异常终止。
不包含有可能在构造函数时抛出异常的成员，这可能会直接导致无法捕获预期类型的异常对象。
有必要时，格式化 what() 或其它成员的输出信息。

@3.6.2.6 异常规范：
在无异常抛出保证(@3.6.2.1.3) 的场合，应使用异常规范。
在非显式使用的异常规范上下文中，使用自定义的异常规范宏代替 throw 关键字。
注意动态异常规范是 ISO C++11 中的 deprecated 特性(@5.1.5) ，应限制使用（如仅用于调试）。
除异常类设计外，不显式地使用异常规范，而用异常规范宏代替。

@3.6.2.7 异常机制实现：
注意 C++ 和底层无 C++ 异常机制实现支持的回调代码的隔离。
注意不同实现的运行时之间不保证兼容。
注意特定平台异常机制和 C++ 异常在语言实现层次上的交互。应保证行为可预期。

@3.6.2.7.1 Windows 结构化异常：
注意扩展关键字和标准关键字的差异。
注意非 C++ 异常捕获的错误可以引起 Windows 结构化异常。

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

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

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

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

@3.7.3 插件系统：
有必要时使用插件系统减少解除耦合性。

@3.8 嵌入语言(embedded language) ：
有必要时使用嵌入语言的解释器或即时编译。注意平衡性能和可配置性需求。

@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 函数对象(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.11.2 谓词(predicate) ：
使用 bool 类型结果的实体称为谓词，包括非成员函数和成员函数及其引用或调用包装，以及类型特征等元函数。

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

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

@4 基于类 C 语言的标识符命名规约(naming convention) ：
以下是默认风格标识符的命名规则和约定。

@4.1 通用指引：

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

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

@4.1.3 拼写和构词原则：
基于兼容性考虑，不使用基本字符集（不另外声明默认为 ASCII ）以外的 Unicode 字符。
以美式英语作为命名标识符的基本自然语言参考。
若不使用以下构词原则或例外，至少应在原始声明处注释。

@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 简单非框架级名称：
在不致混淆的情况下，单字母等（可能是在其它情况下的简单前缀）可以直接作为约束变量（哑变量，如循环变量）或形式参数名称。
下划线和数字组合的名称用于特定模式的参数，类似 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 语言相关的默认限制和使用：
参见 @5.3.2.3 的名称限制，除非另有说明。
 ISO C++ 内建特性相关的名称使用见 @5.3.4 。
其它参见 @4.1 以下小节。

@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 ：更新（完成参数的特定同步操作）。

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

@4.1.7.3 ISO C++ 标准库惯用命名：
包括以下成员类型名：
 size_type ：表示元素数的无符号整数类型；
 difference_type ：表示差值的有符号整数类型；
 const_iterator ：只读语义的迭代器类型；
 iterator ：迭代器类型；
 pointer ：指针类型；
 reference ：引用类型。
包括以下成员函数名：
 begin ：表示起始迭代器。
 end ：表示终止迭代器。
 at ：表示有边界检查的元素访问。
包括以下命名空间作用域函数或函数模板名：
 to_string ：转换为字符串（通常应为 std::string 类型或至少类型名为 string ）表示。
 make_* ：返回特定对象的助手函数（模版）。
包括以下 ISO C++11 成员函数名：
 cbegin ：表示起始只读迭代器。
 cend ：表示终止只读迭代器。
包括以下 ISO C++11 命名空间作用域函数或函数模板名：
 begin ：用于 range based for 的起始迭代器。
 end ：用于 range based for 的终止迭代器。
包括以下可能用于 ISO C++1y 命名空间作用域函数或函数模板名：
 cbegin ：用于 range based for 的起始只读迭代器。
 cend ：用于 range based for 的终止只读迭代器。

@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++ 语用学：
本节表述具体设计内容无关的源代码特性使用和编码风格。

@5.1 概述：
相关概念参见 ISO C++11 Clause 1 。

@5.1.1
禁止程序引起未定义行为(undefined behavior) 。
注意使用未初始化对象具有未决定值(indeterminate value) 。读取未初始化对象的值引起未定义行为。
禁止接口行为依赖于未决定值。

@5.1.2
避免程序的结果依赖于引起未指定行为(unspecified behavior) 的特性。
禁止接口行为依赖于特定的未指定行为。

@5.1.3
需要使用引起实现定义行为(implementation-defined behavior) 的特性时，适当注释。
禁止接口行为依赖于特定的由实现定义行为，除非存在显式的接口使用约束（同时给出注释）。
注意 ISO C++ 中，实现定义行为不是未指定行为的子集，这点和 ISO C 不同。

@5.1.3.1 例外：
可以有少数不显式注释即使用或依赖于通用的实现特性的例外，在这里列出：
对于预处理指令 #include " q-char-sequence" new-line ，假定从源文件的当前路径开始搜索包含项。

@5.1.4
慎重使用有条件支持的(conditionally-supported) 特性。

@5.1.5
禁止使用 ISO C++03 Annex D 中的 deprecated 特性，除以下有说明外；
避免使用 ISO C++11 Annex D 中的 deprecated 特性。
注意以下在前者在前者中作为 deprecated 特性，在后者中被删除（重新支持）的特性，除非必要应避免使用：
 ISO C++03 Annex D.2 static keyword [depr.static] 。
（参见 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3296.html#FI6 。）
应特别注意禁止使用在前者中作为 deprecated 特性，在后者中不支持的特性：
 ISO C++03 Annex D.3 Access declarations [depr.access.dcl] ；
（参见 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3296.html#US56 。）
 ISO C++03 Annex D.4 Implicit conversion from const strings [depr.string] 。
有限使用动态异常规范，参见 @3.6.2.6 。

@5.1.6
注意规避当前语言标准未解决的问题。例如：
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 ，截至 ISO C++11 出版仍是草案状态，通过内建下标操作访问（但不使用值） one-past-end 指针不能确定引起未定义行为（但 ISO C99 中已明确不是）。
上述情况下应该使用指针加法代替下标操作。

@5.1.7 正确性：
合式的(well-formed) 程序遵照三个规则：语法规则、可诊断语义规则和 ODR（One Definition Rule ，唯一定义规则）。
形式非法的(ill-formed) 程序是非合式的程序。
注意一个合式的程序可以包含未定义行为。此时程序不是正确的可移植的程序。
特别注意一个实现虽然一般应拒绝并没有被限定形式非法的程序，但有“无需诊断”(no diagnostic required) 的情况下除外。
 ODR 对于不同的实体(@5.2.1) 的特定使用（称为 odr-used ）具有不同的要求。参见 ISO C++ 3.2 。

@5.1.8 C++ 存储模型：
 C++ 讨论的内存(memory) 明确排除不可按字节(@2.2.2.2) 寻址的存储。一般被实现为主内存。

@5.1.9 C++ 对象模型：
对象具有生存期(lifetime) 和存储期(storage duration) 。
对象具有类型(type) 。
非类类型对象或最终派生类(most derived class) 类型的对象是最终派生对象(most derived object) 。
除了位域(bit-field)，最终派生对象保证占用连续的非零存储单元。一般首个单元对应的即表示对象存储的地址。
不同的对象占据不同的存储单元的完整对象具有不同的地址。

@5.1.10 程序执行：
 ISO C++ 使用抽象机描述程序语义，但不要求实际实现与之完全一致。至少遵循的语义包括对 volatile 对象的访问、程序终止状态和可被动态观察的输入和输出对应的行为，称为可观察行为 (observable behavior) 。
实现的语义遵循 as-is 规则：不影响可观察行为的程序行为可以被实现改变。这是可被允许的一般的优化的根本依据。
表达式的求值(evaluation) 一般意义上包括值的计算(value computation) 和产生副作用(effect) 。
副作用包含对 volatile 对象的访问、对对象的修改和使用 I/O 库函数，表示对环境的改变。
求值的顺序并不一定被确定。任意两个求值之间具有先序(sequenced before) 、不确定有序(indeterminatly sequenced) 或无序(unsequenced) 二元关系之一。
在同一个对象上的无序求值引起未定义行为。

@5.1.11 多线程执行(multi-thread execution) 环境和数据竞争(data race)：
实现可能允许一个程序具有多个并发执行的执行线程(thread of execution) ，简称线程(thread) 。
线程对对象的访问之间可能具有不确定的关系。当无法确定值时产生数据竞争，程序具有未定义行为。使用恰当的同步(synchronization) 避免数据竞争。

@5.2 基本概念及语义：
参见 ISO C++11 Clause 3 和 Clause 5 。注意与 ISO C++03 的区别。

@5.2.1 名称和实体：
区分名称和实体。
注意链接是名称而非实体的属性，尽管也用于命名空间(@5.5.8) 。
关于名称的使用，参见 @5.3.2 。
明确声明引入名称，定义和实体的存在直接相关。
明确定义是声明，但声明不一定是定义。参见 ISO C++ 3.1 。

@5.2.2 对象、变量和值：
对象和变量都是实体。
区分对象和变量。
对象表示存储。
明确变量是通过声明引入的对象。变量具有对象或对象引用类型。
对象具有存储期和生存期。
注意对于非 trivial 构造/析构的对象，生存期始于构造结束，终于析构开始。
注意静态对象的生存期。
注意 POD 对象（包括 ISO C++03 和 ISO C++11 的不同定义）、 standard layout 对象和 trivially copyable 对象，以及它们之间的区别。
注意非 standard layout 或 trivially copyable 对象的使用限制（和 C 存储的交互性， std::memcpy 、 offset 的适用性等）。
了解 scope guard 等和对象生存期相关的惯用法。
值(value) 是由实现定义，没有其它约定的实体。
一个对象的对象表示(object representation) ，以其存储被 N 个 unsigned char 对象连续表示体现，其中 N 等于对象的大小。
一个对象的值表示(value representation) 是特定位的集合，能决定特定的值。因此对象具有存储值(stored value) 。

@5.2.3 值类别(value category) ：
注意值类别是表达式的属性。
注意区分 lvalue 、 xvalue 和 prvalue 。
注意右值引用为 xvalue 的条件。
注意函数表达式的值类别。

@5.2.4 对齐(alignment) ：
对象类型具有对齐要求(alignment requirement) 。
对齐(alignment) 是实现定义的整数值，表示相邻分配对象的最小地址间隔。

@5.2.5 表达式及其求值(evaluation) ：
基本概念参见(@5.1.10) 。
注意非求值操作数(unevaluated operands) 。
注意内建表达式和重载操作符约定的值类别(@5.2.3) 的差异。

@5.3 词法、预处理和内容无关的上下文编码规则：

@5.3.1 源代码文件和字符：
必须保证源代码文件使用的字符集可被实现接受并正确处理（兼容于基本源字符集和基本执行字符集）。
禁止源文件的注释以外部分使用 Unicode 控制字符。
不使用双联符(digraphs) 和三连符(trigraphs)。
行末必须保留至少一个换行符以保证不引起未定义行为。
不过度依赖词法分析的贪婪性。对于多个连续的操作符，必须以无误导性的方式使用空白符分隔。
例如，避免二元/和一元 * 连用导致错误的注释起始标志。

@5.3.2
名称使用限制参见 @5.15.1 。

@5.3.3 名称查找(name lookup) ：
注意查找顺序。
 using 关键字的使用参见 @5.5.7 。

@5.3.3.1 参数依赖查找(argument dependent lookup, ADL) ：
当需要禁止 ADL 时可以使用限定名称或带小括号的名称代替非限定名称。
注意当非限定名查找类成员、非 using 声明的块作用域名称或非函数（模板）名称后 ADL 查找关联名称为空。
不使用冗余的限定名。

@5.3.3.2 依赖名称：
类模板中，显式使用 this 启用依赖名称(dependent name) 的名称查找。
若不需要依赖名称，不使用 this-> 等形式引用名称，以避免可能的错误引用和编译性能下降。

@5.3.4 标识符命名风格：
以下讨论内建特性相关的名称。其它参见 @4 。

@5.3.4.1 range-based for ：
 begin 和 end 被 range-based for 使用。

@5.3.5
其它编码风格参见 @6 。

@5.3.6
有源代码兼容性和可读性良好替代方案的情况下，尽可能不使用宏。

@5.3.6.1
尽可能使用 constexpr 关键字而不是宏定义常量。
尽可能使用 const 关键字定义只读对象。

@5.3.7
使用条件编译控制文件包含，而不是编译器相关的非标准预处理指令（例如 #pragma_once 和 #include_next ）。
除此之外，尽可能不使用条件编译。

@5.3.8
可以使用 #error 、 #warning 和 #line ，但仅使用 ANSI 字符，以免出现不符合的预期文本。

@5.3.9
对于 #include 指令，使用 <文件名> 或 <相对路径> 表示外部库依赖项（仅允许头文件）， "文件名" 或 "相对路径" 表示内部库依赖向（特殊情况下允许源文件，但需在文档中说明目的）。
关于搜索路径，另见 @5.1.3.1 。
在非正式测试等临时用途以外的情况下不使用绝对路径。

@5.3.10
一般应允许使用 #pragma STDC 。
避免 #pragma 后的标识符被作为宏替换为非空记号，以免由实现定义的行为导致的差异。
其它使用 #pragma 的情形由具体项目定义。

@5.4 替代表达保留字(alternative tokens) 、转义字符序列和字面量：

@5.4.1
一般不使用替代表达保留字，以避免导致被替代的标点不够清晰。

@5.4.2 转义字符序列：
使用正确、无歧义的转义字符序列。
注意被转义的字符和基本源字符集之间的关系。
仅在必要时使用八进制或 Unicode 转义字符序列。

@5.4.3
关键字 true/false 和 bool 类型对应；宏 TRUE/FALSE 和 int 类型（例如自定义的 BOOL 类型）对应。
尽可能使用前者。

@5.4.4
非关键字字面量的表达必须保证符合语法，且兼顾可读性。

@5.4.5 零值：
整数用0，浮点数用 0.0 。
空指针用 nullptr （考虑 C 兼容性可以在保证定义正确的前提下使用 NULL ）。
字符（串结束符）用 '\0' 或带前缀的 L'\0' 等表示（其它可选的非字面量的表示形式：对于字符类型 T 使用 T() ； 使用自定义宏 NUL ）。
有必要使用 float 时，用 0.f 。

@5.4.6
合理使用字符串字面量前缀（'L' 、 'u8' 、 'u' 、 'U' 、 'R' 及其组合）。

@5.4.7
可以使用字符串字面量初始化 C 风格字符串。
被初始化的若为字符数组，元素（字符类型）必须是 const 类型修饰的，参见 @5.1.5 。

@5.5 声明和命名空间：
注意区分涉及声明的语法歧义，参见 ISO C++11 6.8 。
注意函数声明和函数定义的区别。

@5.5.1
不使用表示存储类的关键字 auto ，使用编译器的隐式实现。
显式使用会使和 ISO C++11 代码的共用出现问题。

@5.5.2
尽量避免使用存储类关键字 register ，参见 @5.1.4 。
除了平台相关的上下文以外，不使用 register 。
注意 register 仅是建议，而不是命令。

@5.5.3
尽量避免使用静态和全局存储期对象。

@5.5.4 static 和 thread_local ：

@5.5.4.1 命名空间作用域 static ：
注意命名空间作用域的 static 修饰的声明的名称具有内部链接。
避免使用 static 在命名空间作用域声明对象，参见 @5.1.5 以及以下讨论；除非明确需要内部链接且使名称满足特定于实现的需求。
使用翻译单元内的适当的若干未命名命名空间代替，以便自由选择使用内部链接或外部链接，且允许使链接作用于类类型或 typedef 名称等的声明；参见 @5.5.8.1 。
注意 ISO C++03 要求模板非类型实际参数要求名称具有外部链接，参见 ISO C++03 14.3.2/1 ；此时 static 不再适用。但是， ISO C++11 明确命名空间具有的链接(@5.5.8) ，同时也取消了这个限制，参见 ISO C++11 14.3.2/1 。
因此在 ISO C++11 实现中， static 仍然可用，但可能造成混乱，所以避免使用。
为了一致性，一般同时使用未命名命名空间代替命名空间作用域内的 static 函数。
若需要命名空间中声明的名称具有静态链接，可以使用嵌套未命名命名空间(@5.5.8.1) 。但是，现代的实现一般使用 as-if 规则对二进制代码进行优化，它不改变用户程序的可观察行为，所以这种用法并非必要。

@5.5.4.2 类作用域 static ：
注意类作用域 static 用于修饰成员声明，指定其为静态成员，决定其不依赖具体对象。
除非必要，否则不依赖于 this(@5.7.5) 的成员应该为静态成员。
对于成员函数，在类的定义中直接使用 static ，不在类的成员函数定义中重写。
 const 或 constexpr 静态数据成员可直接在类定义内初始化。在没有被 odr-used(@5.1.7) 时不需要定义。这是初始化且不引入定义的唯一特例（关于声明和定义，参见 ISO C++ 3.1 ）。

@5.5.4.3 块作用域 static ：
注意块作用域 static 用于修饰声明的对象，决定其具有静态存储期。

@5.5.4.4 thread_local ：
在可以且有必要使用 thread_local 时，不使用 static 代替。
注意可能和 static 同时使用。
注意 thread_local 允许动态初始化，而实现提供的类似扩展特性可能不允许。
注意对应于 ISO C11 的标识符 thread_local 不是关键字，而以宏形式在标准库头文件 <threads.h> 引入，对应关键字是 _Thread_local 。

@5.5.4.5 和其它关键字连用：
注意 ISO C 中的存储类关键字并不在最前的函数声明被 future language directions 标注为过时。使用如 inline static 的声明，可能引起某些编译器的警告。
在 C++ 代码中一般习惯保持相同的使用顺序。

@5.5.5 extern ：

@5.5.5.1
正确地使用 extern ，并检查语义的合理性。
注意对于之前已有的对象声明， extern 不能直接决定其链接，必须参照之前的声明。
不使用冗余的 extern 。

@5.5.5.2
在多个翻译单元中，extern 声明的类型应保持一致。

@5.5.6 内联 ：

@5.5.6.1 语法：
在必要时使用 inline 关键字。
不使用冗余的 inline （类模板的成员不适用）。
 inline 对于 namespace 的使用参见 @5.5.8.3 。
使用 static inline 而不是 inline static ，使用 thread_local inline 而不是 inline thread_local ；原因参见 @5.5.4.5 。
保持和 static inline 风格一致性，一般使用 explicit inline ，而不是 inline explicit 。

@5.5.6.2 语义：
注意 ISO C++ 规定一个 inline 函数总是应被声明为 inline ，这和 ISO C 不同。
注意 inline 的内联语义对实现只是建议而非强制。此外，不能忽视 inline 对于 ODR(@5.1.7) 的作用。
若能保证不降低源代码的可移植性，在必要时可以使用与编译环境相关的内联语法，但不直接使用非标准的内联关键字，而使用特定的宏定义代替。

@5.5.6.3
不连用 static inline ，而在无名命名空间中用 inline 代替。

@5.5.6.4
在类的成员函数声明中可以省略 inline 关键字，参见 ISO C++03 7.1.2/3 。
若类的成员函数声明和定义分离，在完整定义而不是声明处使用 inline 。

@5.5.6.5 inline 函数名的链接：
注意 ISO C 和 ISO C++ 对于 inline 函数的链接的差异。 ISO C 的 inline 函数默认具有内部链接，而 ISO C++ 的内联函数默认具有外部链接。
按 ISO C++03 7.1.2 Function specifiers [dcl.fct.spec] 规定可知，非外部链接的内联函数内的局部静态对象不是同一对象。
按 ISO C++03 3.5 Program and linkage [basic.link] 规定可知，非外部链接的嵌套类名的成员函数不具有外部链接。
因此需要注意当使用内联成员函数且在其中定义静态对象时类名具有的链接。

@5.5.7 using ：
注意 using 声明优先于 using 指示。

@5.5.7.1 using 声明：
不使用冗余的 using 声明。
尽量避免在命名空间作用域内，尤其是头文件中使用 using 声明，以防名称污染。
在结构体/类中合理使用 using 声明使被隐藏成员可见，此时需要注意访问权限控制(@5.13.5) 。

@5.5.7.2 using 指令：
除非特别指定（例如文档说明），应避免在命名空间作用域内，尤其是头文件中使用 using 指令，以防名称污染。

@5.5.8 命名空间：
注意命名空间是实体，但具有链接。
注意命名空间具有作用域。
注意 ISO C++11 3.5/3 明确，命名空间具有的链接对其中声明的、名称未被指定为内部链接的特定实体（变量、函数、命名类、具有 typedef-name 的未命名类、命名枚举、具有 typedef-name 的未命名枚举、具有链接的枚举中的枚举项和模板）具有传递性。
注意全局命名空间。

@5.5.8.1 未命名命名空间(unnamed namespace) ：
注意可能 ISO C++03 中未命名命名空间具有外部链接，但可能被实现优化，如。
注意 ISO C++11 3.5/4 明确，未命名命名空间及其中直接或间接的命名空间具有内部链接。
根据 @5.5.8 讨论的规则，未命名命名空间中的名称具有内部链接。

@5.5.8.2 命名空间别名：
尽量避免命名空间别名造成的名称歧义。

@5.5.8.3
在 ISO C++11 实现及启用某些扩展的视线（如 Clang++ ）中，可使用 inline 于命名空间，用于区分版本等。

@5.5.9 友元：
禁止在类定义中定义友元类。
为保证代码清晰，一般不在类定义中定义友元函数。
除了以下提及的用法，避免使用友元。

@5.5.9.1 突破封装性的访问权限限制(@1.3.6.2) ：
友元无视访问权限控制限制。

@5.5.9.2 名称查找：
友元被允许 ADL(@5.3.3.1) 查找。
参见 http://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick 。

@5.5.10 修饰函数/函数模板的 constexpr ：
注意使用 constexpr 的语法和语义限制。
和 static 、 explicit 配合使用时类同 inline ，参见 @5.5.6.1 。

@5.6 const 和 volatile 限定符(cv-qulifier) ：

@5.6.1 const ：
注意无 extern 时命名空间作用域声明的 const 对象名称具有内部链接，这点和 ISO C 不同。
若有可能，尽可能使用 const 关键字，除了以下给出的例外(@5.6.3) 。

@5.6.2
仅在有必要时使用 volatile 关键字。

@5.6.3 例外：
使用 constexpr 时不使用 const ，除保留修饰成员函数的 const 外。
可使用 constexpr 或 const 时尽量使用 constexpr 而不是 const ，除非有必要考虑兼容性。
在函数参数列表中，省略不直接修饰参数的 const 。
在异常捕获块和异常规范中，省略形式参数顶层的 const 和 volatile 修饰符。
函数参数类型在语义上有必要时，考虑不使用 const ，参见 @5.11.2 。

@5.7 类型关键字和模板：

@5.7.1
除非有必要，用非整数类型代替浮点数类型。

@5.7.2 整数类型：

@5.7.2.1 大小：
当需要时使用确定大小的整数类型。优先使用 <cstdint> 中支持的类型。

@5.7.2.2 符号和存储表示：
在位运算时尽量使用无符号整数。其它情况按需选取有符号数。
注意 ISO C/C++ 支持原码、反码或补码的有符号数表示的实现。多数实现使用补码。

@5.7.2.3 整数与指针类型：
注意指针类型和整数类型的大小不保证相等。
需要使用和对象指针占用空间大小相同的整数类型时，若实现支持（可选支持，参见 ISO C++11 18.4.1 ），使用 std::intptr_t 或 std::uintptr_t 。

@5.7.2.4 字符类型：
 ISO C++98/03 支持 char 和 wchar_t 作为内建支持的字符类型。 ISO C++11 新增 char16_t 和 char32_t 类型，一般用于表示 Unicode 字符。
 ISO C/C++ 中， char 类型实际定义了字节的大小，即 sizeof(char) == 1 ，且具有 CHAR_BIT （注意 CHAR_BIT 不小于 8 ）二进制位。
注意 ISO C/C++ 中，和其它能被 signed 或 unsigned 修饰的整数类型不同 signed char 、 unsigned char 和 char 具有相同的大小和对齐要求，但是三种不同的类型。
除了 char 以外的内建字符类型关键字不被 signed 或 unsigned 修饰。
注意 sizeof(wchar_t) 平台相关。而 char16_t 和 char32_t 分别表示至少能存储 16 位和 32 位二进制整数，并不表示确切的大小。

@5.7.3 枚举类型：
注意带作用域枚举(scoped enumeration) 在声明时不能省略作为枚举名称的标识符（参见 ISO C++11 7.2/2 ）。
 enum class 和 enum struct 语义等价（参见 ISO C++11 7.2/2 ），统一风格起见应尽可能使用 enum class 。

@5.7.4 class-key ：
关于带作用域枚举，参见 @5.7.3 。
根据基类和成员的可访问性(@5.13.5) 的需要适当选择 struct 或 class 。
对于同一个非 union 实体，在声明中总是一致地使用 struct 或 class 之一，以免某些非标准实现（如某些版本的 Microsoft C++ ）产生诊断消息。在某些实现启用诊断消息检查（如 Clang++ 使用 -Wmismatched-tags 警告）。

@5.7.5 this ：
注意 this 是实体（参见 ISO/IEC 14882 Clause 3 ）。
注意 this 的类型。
关于类模板中的使用，参见 @5.7.6 。

@5.7.6 模板声明中的关键字使用：
在定义模板类型（非模板）参数时 class 和 typename 等价，但应根据语义适当选择，以提升可读性：
若能确定模板类型参数仅适用于 class 类型（例如内部对此模板参数使用 std::is_class 等的静态断言），使用关键字 class ；否则使用关键字 typename 。
注意模板模板参数时的语法要求，适当使用 template class 。
不使用 export 。此特性在 ISO C++11 中被删除，但 export 关键字仍被保留。由于实现的限制，多数实现无法支持这一 ISO C++03 标准特性。
关于依赖名称，参见 @5.3.3.2 。

@5.7.7 模板名称：
注意除了成员函数模板外的模板名称具有外部链接。

@5.7.8 模板的实例化和特化：
注意特化的结果包含实例。
适当使用 ISO C++11 引入的显式实例化声明(extern template declaration) 以节约编译时开销。
注意模板的特化的链接。

@5.8 操作符和内建操作：

@5.8.1
尽可能用对象名称代替类型名称作为 sizeof 的操作数，以在重编码时保持一致性。

@5.8.2 操作符重载：
参见 @5.12.3 。
注意内建操作和重载操作符在操作数要求值类别和求值顺序等限制不同。

@5.8.3 算术操作：

@5.8.3.1 算术转换：
注意算术转换，特别是算术操作数被提升为 int 类型。

@5.8.3.2 溢出：
注意有符号数溢出是未定义行为。
四则运算、取余和移位均可能导致溢出。
除数为 -1 可导致溢出，如 http://kqueue.org/blog/2012/12/31/idiv-dos/ 。
注意 n 位无符号数保证不溢出而保证结果回绕为 2 ^ n 的余数。

@5.8.3.3 浮点数：
注意浮点数的舍入误差、非数值（如 NaN 和 Inf 等）和浮点环境。

@5.9 声明符和初始化：
注意区分涉及声明符的语法歧义，参见 ISO C++11 8.2 。

@5.9.1 声明符：
注意声明符的递归形式。
除非必要，避免使用复杂的声明符。

@5.9.2
区分直接初始化和复制初始化。

@5.10 语句和控制流：
编码时应注意避免干扰实现的分支预测优化。必要时可使用经过包装的特定实现的扩展。

@5.10.1 判断：
合理使用 if 语句代替 if-else 语句。

@5.10.2 无条件跳转：
尽可能不使用 goto ：仅在退出多层循环等少数具有明确语义且没有高效结构化控制流替代方式时使用。

@5.10.3 多分支：
合理减少 switch 块中的 break 个数。

@5.10.4 for 语句：

@5.10.4.1 for-init-statement 子句：
可使用以“ = ”起始的初始化。
但若不需要和 C 兼容，考虑类类型的这种形式具有的复制初始化语义，应尽量以直接初始化（标识符后直接接“ ( ”或 C++11 支持的“ { ”）代替，而避免使用“ = ”。

@5.10.4.2 condition 子句：
基于 C 兼容性和代码一致性考虑， condition 子句使用初始化（以“ = ”起始）。

@5.10.4.3 range-based for ：
注意适当使用 begin 和 end 重载函数配合 range-based for 的使用。

@5.10.5 异常：
参见 @3.6.2 。

@5.10.6
除非必要，不使用 <csetjmp> 。

@5.11 类型操作：

@5.11.1
注意参数传递中的退化：数组到指针，函数到函数指针。
可以使用 std::decay 显式实现。

@5.11.2
禁止使用变长数组，除非兼容性需要。

@5.11.3
使用 C++ 风格而不是 C 风格的类型转换。

@5.11.4 显式类型转换：
注意 dynamic_cast 依赖于运行时类型识别(RTTI) ，需要多态类(@5.13.3) ；而其它三个关键字表示的转换在编译时确定，无此限制。
若有可能，使用 dynamic_cast 代替 typeid ；
若有可能，使用 static_cast 代替 dynamic_cast ；
若有可能，使用 static_cast 代替 reinterpret_cast 。
接口类型(@1.6.1) 转换可选 dynamic_cast ，但能保证类型安全且不被虚继承时首选 static_cast ，以提升性能。
如果可能（对于 simple-type-specfier 和 typename-specifier ），一般应使用函数调用形式代替 static_cast ，以保持简洁。
注意 const_cast 禁止用于转换 const 动态类型的对象，以免引起未定义行为。
注意在函数指针和对象指针之间的 reinterpret_cast 是有条件支持的(@5.1.4) 。

@5.11.5
禁止对派生类的成员指针使用转换为基类成员指针的 static_cast ，以避免成员指针实现相关的错误。

@5.12 函数/模板参数和重载：
注意函数重载和默认参数的使用的清晰性和易读性。

@5.12.1
避免不必要的重载和歧义。

@5.12.2 参数类型：
除非以下讨论的语义上的必要性，不使用 const 左值引用类型以外的参数类型。
在需要完全的值类型语义且复制开销较小（例如传递一个内建整数类型的对象、内建指针、典型的迭代器、常见的函数对象）时，使用非引用类型形式参数。
在需要转移语义时，使用非 const 右值引用类型参数，同时使用 std::move 或等价的显式类型转换包装参数传递。
仅向内部实现中的调用传递参数，外层参数使用非 const 右值引用类型时，同时使用 std::forward 或等价的显式类型转换包装参数传递。
关于复制赋值/转移赋值，参见 @5.11.3.2 。

@5.12.3 操作符重载：

@5.12.3.1 限制特定的重载：
除非必要，不重载一元 operator& 和 一元 operator* 。若重载，需要和内建操作符的对应语义相关。
一般不重载 operator->* 和 operator, 。若重载，需要特别注意优先级。
二元操作符一般重载为非类成员，其它操作符一般使用重载为类成员。

@5.12.3.2 重载 operator= ：
注意 operator= 被派生类隐藏。
注意复制赋值函数和转移赋值函数是特殊成员，可以声明为 =default 。
转移赋值一般应保证无异常抛出(@3.6.2.1.3) 。
除非有特别说明，不应依赖转移赋值不引起实际参数状态的改变。
其它赋值无特殊限制。
经典复制赋值实现使用 copy-and-swap idiom 和 const 左值引用参数，能避免自赋值副作用且至少具有强异常安全性保证(@3.6.2.1.2) 。
由于异常规范仅适用于块，不涉及参数复制的异常，因此当函数体内保证无异常抛出时，可以直接使用无异常抛出保证的异常规范。
通过使用非引用参数代替 const 左值引用的 operator=(unifying assignment operator) ，可以获得对象复制的优化，但具有以下缺点：
重载右值引用参数的 operator= 会引起重载歧义，即无法通过单独重载优化的转移赋值（对于转移赋值，使用 copy-and-swap 需要多一步复制/转移构造）；
无条件复制，无法根据被复制的对象的状态进行优化；
若没有 trivial 复制赋值，没有转移赋值会导致以此类对象作为成员的类无法使用默认生成转移赋值（隐式地，或声明为 = default ，都相当于 = delete ）。
因此，除非被复制的对象具有完全的（所有子对象均满足）值语义，一般不重载非引用参数的 operator= ，而分别重载 const 左值引用参数和非 const 右值引用参数的版本（也可能不需要转移赋值，仅重载前者）。
若转移赋值是必要的，一般应确保存在可访问的转移构造函数。
对于保存存储状态的不完全值语义对象（例如容器），使用最小赋值：在 operator= 的实现中判断状态，以避免分配不必要的存储空间。
对于其它不完全值语义对象，若转移赋值是必要的，使用以下实现：
具有明确的 clear 操作回复值的状态时，使用判断自赋值的 clear-and-swap 实现，可以期望比 copy-and-swap 具有更好的性能（因为通常不需要大量 clear 操作）；
当不需要 clear 操作回复状态（例如约定调用方保证参数是临时对象）时，可直接 swap ；
其它情况使用默认简单实现，即对每个子对象进行转移赋值（可以显式使用 = default ）。

@5.12.3.3 重载自增和自减：
在相同作用域内，前置和后置自增/减被同时定义时，尽量保证它们的语义一致性，并通过前置自增/减来实现后置版本。若有必要改变，必须给出注释说明。
能使用前置自增/减实现相同效果时，不用后置自增/减。

@5.12.3.4 重载 operator() ：
允许多个重载 operator() 。应特别注意成员 operator() 的 cv-qualifier 。
当存在多个重载候选时，通过 std::enable_if 或其它 SFNIAE 进行选择。若无法选择，调用其它成员（模板）。

@5.12.3.5 重载转换操作符：
允许重载操作符模板。应特别注意成员 operator() 的 cv-qualifier 。
当存在多个重载候选时，通过非模板优先于模板匹配进行有限选择。若无法选择，调用其它成员。

@5.12.4 默认参数：
合理地使用函数默认参数。需要注意参数顺序。

@5.12.4.1
在虚函数中应避免使用默认参数。
若需要使用默认参数，应在基类中使用具有默认参数的非虚成员函数调用没有默认参数的非 public 虚函数。

@5.13 类：
类是类型。
类类型包含 class 和 union 。

@5.13.1 类名：
类名声明不是定义。
类名声明引入的类是不完整类型。

@5.13.2 类的成员：
静态成员函数同非成员函数，除了受到访问权限控制(@5.13.5)  的作用。
非静态成员函数操作受限。

@5.13.3 派生类：
注意空基类优化：基类子对象可能占用零存储。
继承和访问权限控制(@5.13.5) 相关。注意 C++ 中，类的成员是否被继承不受权限控制的影响。 
具有虚函数或虚基类的类是多态类。适当平衡运行时开销。
虚基类的初始化顺序和非虚基类不同。

@5.13.4 特殊成员函数：
注意排除模板。
区分隐式声明和定义。
注意 ISO C++11 关于隐式声明复制构造函数和复制赋值操作符的 deprecated 特性。
注意 ISO C++ 构造函数中的虚函数调用行为同非虚函数，这和 Java 、 C# 、 C++/CLI 和早期的非标准 C++ 的类似特性不同。

@5.13.5 访问权限控制：
访问权限控制决定可访问性。
注意访问权限控制和可见性相互独立。
注意对于一般实现，访问权限控制仅在编译时检查。
关于友元，参见 @5.5.9 。

@5.13.5.1 默认访问权限：
注意 class 默认具有 private 、 struct 默认具有 public 。
访问权限控制对大多数成员声明能体现实际语义，因此不依赖于省略默认访问权限。例外是友元声明和 static_assert 声明，对此无论何种访问权限都不显式改变语义，因此这些声明应出现在类定义中的第一个 access-specifier 前。

@5.13.5.2 访问权限选择策略：
本节的语义包括领域逻辑语义和语言限定的其它语义。
对于语义要求公开的接口，使用 public 。
对于语义要求非公开的接口，尽量使用 private ，其次使用 protected ，若存在实现限制则使用友元。
注意数据成员同时体现直接读写访问的接口。若需要不同层次的读写访问权限，应该使用 private 保护数据成员，同时使用访问器(accessor) ，即 getter 和/或 setter 满足不同的需要。
对于其它成员，若没有明确限制接口非公开，在能保证访问清晰明确时首先使用 protected 代替 private ，以避免实现可能不必要的间接适配（调用）层次的负担。最小接口(@3.1.3) 在之后的重构时体现。
对于体现 LSP（Liskov Substitution Principle ，里氏替换原则）的空开接口继承，使用 public 。
对于实现混入(mixin) 但需要由派生类定制的基类继承，使用 protected 。
对于其它体现实现的继承，使用 private 。

@5.13.6 虚函数：

@5.13.6.1 覆盖(overriding)：
虚函数可以使用显式的 qualified-id 进行调用以取消动态多态，否则虚函数调用最终覆盖版本(final overrider) 。
注意避免函数签名的修饰符差异导致遗漏覆盖。
注意虚函数的覆盖不影响访问权限。

@5.13.6.2 纯虚函数：
纯虚函数是特殊的虚函数。
没有非虚覆盖版本的纯虚函数导致所在的类是抽象的，无法构造对象。具有虚析构函数，非静态成员函数都是纯虚函数的抽象类，可作为接口类型(@2.4.1) 使用。
注意 C++ 的纯虚函数的定义可选，一般用于提供默认实现。

@5.13.6.3 NVI（Non-Virtual Interface ，非虚接口）模式：
虚函数不一定需要作为公开接口。此时，用 private 或 protected 保护虚函数不被外部访问。
具体选择 private 或 protected 虚函数取决于是否确定需要显式 qualified-id 调用(@5.13.6.1) 影响。其它选择策略参见 @5.13.5.2 。
以调用虚函数的基类的成员函数提供访问时，实现模版方法(template method) 模式。
以友元调用虚函数时，实现虚友元(virtual friend) 模式。

@5.14 I/O 操作：
注意 I/O 操作是副作用。
其它参见 @5.15.2 。

@5.15 标准库：

@5.15.1 名称使用限制：
本节“实现”指 C++ 核心语言和标准库实现。
除非另有说明，本节中引用的标号分别表示 ISO C++03 和 ISO C++11 同时对应且内容一致的章节（若标号相同则只使用一个）。

@5.15.1.1 命名空间使用：

@5.15.1.1.1 namespace std ：
按 ISO C++03 17.4.3.1 Reserved names [lib.reserved.names] 和 ISO C++11 17.6.4.2.1 Namespace std [namespace.std] 规定，对全局命名空间 std 的使用受限，仅允许在满足其它条款需求时添加模板的特化。

@5.15.1.1.2 namespace posix ：
按 ISO C++11 17.6.4.2.2 Namespace posix [namespace.posix] 规定，全局命名空间 posix 及其中的名称保留给实现使用。

@5.15.1.2 保留名称：

@5.15.1.2.1
按 17.4.3.1.1/17.6.4.3.1 Marco Names [lib.extern.names] 规定，可能使用标准库头文件的用户程序翻译单元不得使用词法上等价于关键字的名称作为宏名。

@5.15.1.2.2
按 17.4.3.1.2/17.6.4.3.2 Global Names [lib.global.names] 规定，以下名称保留给（核心语言和标准库）实现使用：
包含连续双下划线 "__" 或以下划线 "_" 紧接大写字母起始的名称；
在全局命名空间和 ::std 命名空间内以下划线 "_" 起始的名称。

@5.15.1.2.3
按 17.4.3.1.3/17.6.4.3.3 External linkage [lib.extern.names] 规定，以下名称保留给（核心语言和标准库）实现使用：
在头文件中，在 std 命名空间或在全局命名空间的具有外部链接的对象名称，例如 <cerrno> 中定义的 errno ；
在头文件中，具有外部链接的全局函数签名；
外部链接的全局命名空间的对象和函数以及 std 命名空间的对象；
具有 extern "C" 或 extern "C++" 链接的包含连续双下划线 "__" 的名称；
 C 标准库(Standard C library) 使用的具有 extern "C" 链接，在 std 命名空间或在全局命名空间的名称；
 C 标准库(Standard C library) 声明的具有 extern "C" 或 extern "C++" 链接，在全局命名空间的函数签名。

@5.15.1.2.4
按 17.4.3.1.4/17.6.4.3.4 Types [lib.extern.types] 规定，对于 C 标准库的每一个类型名称 T ， ::T 和 std::T 保留给实现使用。

@5.15.1.2.5
禁止使用 override 、 final 、 carries_dependency 和 noreturn 作为宏名，参见 ISO C++11 C.2.7 Clause 17: library introduction [diff.cpp03.library] 。

@5.15.2 ISO C++11 直接指定的依赖项：
本节“包含”的含义参见 ISO C++11 17.6.5.2/1 ，即被指示为包含的头文件中的标准库接口的声明和定义保证和包含此头文件等效。

@5.15.2.1 由 Synopsis 节显式指定：
 <algorithm> 、 <array> 、 <deque> 、 <forward_list> 、 <list> 、 <map> 、 <queue> 、 <set> 、 <stack> 、 <random> 、 <regex> 、 <string> 、 <unordered_map> 、 <unordered_set> 、 <valarray> 、 <vector> 、 <utility> 包含 <initializer_list> ；
 <ios> 包含 <iosfwd> ；
 <bitset> 包含 <string> 和 <iosfwd> ；
 <isotream>包含 <ios>、<streambuf>、<istream>、<ostream>。

@5.15.2.2 补充指定：
 ISO C++11 24.6.5/1 指定，除 <iterator> 外，以下头文件被包含时 24.6.5 的函数模板（即 std::begin 和 std::end ）也可用：
 <array> 、 <deque> 、 <forward_list> 、 <list> 、 <map> 、 <regex> 、 <set> 、 <string> 、 <unordered_map> 、 <unordered_set> 和 <vector>.

@5.15.3 C 标准库：
不使用 ISO C 标准库头文件名，以 ISO C++ 对应无扩展名的头文件代替。注意命名空间。

@5.15.3.1 内存管理：
如无必要，不使用 realloc 。
注意 ISO C 标准库关于内存分配的设计遵循无隐式 malloc 规则(no-implicit-malloc rule) ，而 POSIX 和其它实现忽略（参见 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1106.txt )。

@5.15.4 迭代器：
注意迭代器的类别(category) 。
注意 std::iterator 的继承应该为 public 继承，否则需要显式在派生类中声明类型名以免失效。对于迭代器类模板，依赖名称(@5.3.3.2) 若作为 std::iterator 的参数，总是需要重新声明。

@5.15.5 C++ 标准 I/O
可以同时使用 C++ 标准流和 printf/scanf 函数族进行格式化输入/输出处理，但在考虑效率（以及目标文件大小）时应尽量避免使用 C++ 标准流。
应注意 nifty counter idiom(http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter) 对多翻译单元程序大小的影响。
正确使用 printf/scanf 函数族格式化输入输出的控制字符。

@6 类 C 语言编码风格导引：
仅叙述之前章节未涉及的内容。
源代码外观仅考虑使用等宽字体的水平显示。

@6.1 字符和编码：
禁止使用的字符参见 @5.3.1 。
源代码文件的默认编码使用 UTF-8 ，其它情况需要说明，否则视为临时文件。

@6.2 预处理记号：

@6.2.1
不使用双联符(digraph) 和三联符(trigraph) 。

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

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

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

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

@6.3.1 段落缩进：
块使用缩进。
命名空间的直接成员不使用缩进。
标签不使用缩进。
初始化列表的 : 前使用缩进。
其它非预处理代码（如语句、函数或模板形式参数列表、类或类模板定义的成员列表）若需要换行，第二行起使用缩进。

@6.3.2 换行后缩进：
非复合语句换行后使用缩进。
紧接在续行符后的下一个文本行使用缩进，除非断行在字符串字面量内部。

@6.4 分行：

@6.4.1
默认行宽 80 个半角字符。
标识符的使用应注意（考虑缩进和对齐后）不超过此限制。其它情况下可以使用行尾的续行符 \ 进行断行连接。
必要时可以同时使用字符串字面量和断行连接。

@6.4.2
除特殊情况外，任意不同语句（包括复合语句和块的第一个子语句）应起始于不同行。

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

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

@6.4.3 列表分行：
本节约定列表语法（ISO C++ 中 -seq 或 -list 结尾的语法元素），包括语句、函数或模板形式参数列表、类或类模板定义的成员列表、初始化列表等的分行规则，需要满足以上规则及 @6.5 。
为了描述方便，本节视列表组成元素结尾可选或之后紧接的分隔符（如 , ）包含于列表项。
分行策略按需进行。

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

@6.4.3.2 非紧缩分行：
每一个列表项需要独立占一行。

@6.4.3 空行：

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

@6.4.3.2
在 @5.3.1 的基础上，在源代码文件尾留空行；默认为 2 行。

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

@6.4.3.4
类类型定义、枚举类型定义和函数/函数模板定义之间应该保留空行，具有特定关联（如同名重载）的函数/函数模板定义之间除外。

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

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

@6.4.3.6
模板声明中 template 和被声明的模板名称及模板修饰符以外的修饰符不在同一行，即模板形式参数列表至少占一行。

@6.4.3.7
不使用复杂函数声明符，保证函数声明符能拆分成返回类型和非返回类型（包含参数列表）两部分。
函数及函数模板声明中的返回类型和函数修饰符独占一行。

@6.4.4 注释：

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

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

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

@6.4.4.4
在非临时的源代码文件头部加入版权声明。

@6.5 分词：
除 @6.3 和 @6.4 外，仅使用空格分隔记号。
除 @6.5.2 ，一个记号的所有字符应保证在同一行内。
除非使用多声明符的声明符列表，同一行内的声明符或抽象声明符的 * 和 & 都向左和语法元素靠拢，和右边的语法元素保持一个空格。
除字面量中，空白符不出现于行尾。

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

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

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

*/
////

