﻿/*
	© 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 LanguageConvention.txt
\ingroup Documentation
\brief 语言使用规约。
\version r1653
\author FrankHB <frankhb1989@gmail.com>
\since build 543
\par 创建时间:
	2012-10-08 05:13:05 +0800
\par 修改时间:
	2016-06-08 07:00 +0800
\par 文本编码:
	UTF-8
\par 模块名称:
	Documentation::LanguageConvention
*/


/*

@0 体例和适用范围：
引用标记参见 [Documentation::CommonRules @@0.1] 。
本文档适用于一般开发，用于促进程序代码中可预期的良好性质。

@0.1 可读性(readability) ：
基本概念参照 [Documentation::CommonRules @@0.3] 。
本文档限定：可读性是能减少语法(syntax) 和语义(semantics) 噪音至可接受程度内的性质，是可预期的良好性质(@0) 之一。
语法和语义噪音是程序代码表现的对代码作者原始意图的偏离。

@1 绪论：

@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 10815:2006, Information technology — Programming languages, their environments and system software interfaces — Technical Report on C++ Performance
— 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 引用简写：
CWG ： WG21 Core Working Group (Issues) 。
ISO C ： ISO/IEC 9899 ；
ISO C90 ： ISO/IEC 9899:1990 ；
ISO C99 ： ISO/IEC 9899:1999 ；
ISO C11 ： ISO/IEC 9899:2011 ；
ISO C++ ： ISO/IEC 14882 ；
ISO C++98 ： ISO/IEC 14882:1998 ；
ISO C++03 ： ISO/IEC 14882:2003 ；
ISO C++11 ： ISO/IEC 14882:2011 。
LWG ： WG21 Library Working Group (Issues) 。
POSIX.1 ： IEEE Std 1003.1 ；
POSIX.1-2004 ： IEEE Std 1003.1-2004 。
SUS ： Single UNIX Specification 。
WG21 ： ISO/IEC JTC1/SC22/WG21 。

@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 语言实现的兼容性和互操作性：
仅在特定必要情形下使用语言/方言实现之间的的互操作特性。
注意可以是相同语言（如 C++ ）之间进行互操作。
关于 C 和 C++ ，参见 @3 。
另见 [Documentation::CommonRules @@3.7.3] 。

@2.1 ABI（Application Binary Interface ，二进制应用接口）及其兼容性：
对保证 ABI 兼容性提供文档说明。
不假定没有文档约定的二进制兼容。

@2.2 ISA（Instruction Set Architecture ，指令集架构）：
仅在必要时使用汇编语言或机器指令，包括内联汇编或 shellcode 。
不假定相同 ISA 的不同实现具有完全一致的特性。不依赖这些实现的专有特性。

@3 C 和 C++ ：
ISO C++ 和 ISO C 的兼容性参见 ISO C++ Annex C 。
注意一般 C++ 实现同时是 C 实现。这些实现一般可通过扩展名默认区分翻译单元使用的语言。

@4 C 语言使用规约：
略。另见 @3 和 @5 。

@5 C++ 语言使用规约：
本节表述具体设计内容无关的源代码特性使用和编码风格。
除非另行约定， ISO C 指所有 ISO C90 及之后版本都兼容适用的规则， ISO C++ 指所有 ISO C++98 及之后版本都兼容适用的规则。
所有没有明确指定的规则基于 ISO C++03 。

@5.1 概述：
相关概念参见 ISO C++11 Clause 1 。
若实际代码与本章的规则不一致，则应以文档或代码附近的注释显式说明不遵守的充分理由。

@5.1.1
禁止程序引起语言标准指定的未定义行为(undefined behavior) ，除非为以下情形之一，且另有文档说明：
明确依赖定义了明确行为并作为扩展的兼容标准；
明确可使用的特定平台环境；
依赖特定平台环境的语言实现，保证可预期的行为，且不违反公开接口约束（如内部实现使用的 noexcept 保证不被违反时，可指定实现省略检查）。
注意使用未初始化对象具有未决定值(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 区域(locale) ：
除非显式指出，总是使用默认区域（ "C" （。
不依赖区域特定的行为(locale-specific behavior) ，除非另有文档说明。

@5.1.5
慎重使用有条件支持的(conditionally-supported) 特性。使用时必须有文档说明。

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

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

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

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

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

@5.1.11 程序执行：
ISO C++ 使用抽象机描述程序语义，但不要求实际实现与之完全一致。

@5.1.11.1 可观察行为：
至少遵循的语义包括对 volatile 对象的访问、程序终止状态和可被动态观察的输入和输出对应的行为，称为可观察行为 (observable behavior) 。

@5.1.11.2 as-is 规则和程序优化：
实现的语义遵循 as-is 规则：不影响可观察行为的程序行为可以被实现改变。
这是可被允许的一般的优化的根本依据。
ISO C++ 提供的唯一其它优化依据参见 @5.13.4.3 ：注意可能影响可观察行为。

@5.1.11.3 表达式的求值(evaluation) ：
表达式的求值一般意义上包括值的计算(value computation) 和产生副作用(effect) 。
副作用包含对 volatile 对象的访问、对对象的修改和使用 I/O 库函数，表示对环境的改变。
求值的顺序并不一定被确定。任意两个求值之间具有先序(sequenced before) 、未决定有序(indeterminatly sequenced) 或无序(unsequenced) 二元关系之一。
在同一个对象上的无序求值引起未定义行为。

@5.1.11.4 信号处理(signal handling) ：
ISO C11 明确信号处理函数中，除了 volatile std::sig_atomic_t 类型的对象或无锁操作的原子对象以外对象的值以及浮点环境状态未指定。
ISO C++11 要求信号处理函数只能修改 volatile std::sig_atomic_t 类型的对象或无锁操作的原子对象。
之后的修订取消了这个限制，指定通过 raise 函数引起的信号处理函数后于调用，先于返回 [WG21 N3910, WG21 N3936]。
当前只使用正式标准规定的定义。另见 @5.15.3.2 。

@5.1.11.5 I/O 操作：
注意 I/O 操作是副作用。
另见 @5.15.14 。

@5.1.12 多线程执行(multi-thread execution) 环境和数据竞争(data race) [ISO C++11] ：
实现可能允许一个程序具有多个并发执行的执行线程(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 的条件： xvalue 是右值对象引用。
注意函数表达式的值类别。

@5.2.4 类型(type) ：
C++ 的类型包括 void 类型、对象类型、函数类型和引用类型。
注意类型可被限定符修饰，限定符可影响类型，参见 @5.6 。
类型关键字、静态类型推导（模板以及 C++11 关键字 auto 和 decltype ）参见 @5.7 。

@5.2.4.1 右值引用(rvalue reference) 和转移语义(move semantics) ：
右值引用是 ISO C++11 支持的新的引用类型。
关于右值引用和值类别的关系参见 @5.2.3 。
非 const 右值对象引用用于实现转移语义。
注意一般地，转移语义仅保证转移后目标的后置条件。
除非另行约定，函数参数类型的使用满足 ISO C++11 17.6.4.9 Function arguments [res.on.arguments] 的规则。
按 ISO C++11 17.6.5.15 Moved-from state of library types [lib.types.movedfrom] 规定，被转移的对象在操作后的状态可能有效但未指定(valid but unspecified) 。
大多数标准库定义的类型的对象被转移后为有效但未指定状态，如满足 MoveConstructible 的对象在未另行指定时被转移后的状态；
相反的例子，如标准库的 std::unique_ptr （通过所有权转移约定）和 std::shared_ptr （通过转移构造函数约定），保证被转移后的对象为空。
另见 @5.12.2.3.1 。

@5.2.4.2 引用折叠(reference collapsing) 和完美转发(perfect forwarding) ：
引用折叠是 ISO C++11 引入的特殊引用规则。对特定上下文（如 typedef 和 decltype 组合引用类型）中，被左值引用修饰的引用类型为左值引用，被右值引用修饰的右值引用类型为右值引用。
在函数模板类型推导时，对模板类型参数 T ，对应形式上为右值引用声明符的函数类型参数 T&& 启用特殊规则，能保证实例化的函数形式参数保持和实际参数相同的 cv-qualifier 和值类别，因此实现完美转发：无需对每个 const 或左值引用/右值引用提供单独的重载版本。

@5.2.4.3 限制使用：
在有更合适的替代时，限制使用不利于表达清晰语义的类型。

@5.2.4.3.1 内建指针：
一般地，内建指针仅在互操作以及语言或标准库要求使用时必要。
注意以下情形不适用指针而优先使用其它更清晰表达意图替代：
表示具有所有权的资源，使用智能指针(@5.15.9) ；
引用无所有权的参数，使用内建引用；
表示迭代操作或范围，使用迭代器为基础的类型；
尽量使用 nullptr(@5.4.5) 表示空指针常量。
简化起见，非所有权的弱引用可以使用指针。

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

@5.2.6 表达式及其求值(evaluation) ：
基本概念参见(@5.1.11) 。
注意非求值操作数(unevaluated operands) ，其中不发生求值，没有副作用。
注意内建表达式和重载操作符约定的值类别(@5.2.3) 的差异。
注意函数类型等价性，尤其是讨论重载时；参见 @5.12.1 。

@5.2.6.1 lambda 表达式 [ISO C++11] ：
注意 lambda 表达式中的捕获变量规则。
没有捕获的 lambda 表达式存在非 explicit (@5.12.1) 到函数指针的转换操作符。
lambda 表达式转换的函数指针具有 C++ 语言链接(@5.5.5.3) [CWG 1557, WG21 N3690] 。

@5.2.6.2 算术操作：
注意 ISO C++ [expr.add] 规定指针算术越界为未定义行为。

@5.2.6.3 比较操作：
内建比较操作对内建指针的结果只提供有限保证。
注意在 ISO C 中，非同一聚集或联合对象内的元素且非超过数组末尾一个元素(one-past-end) 的指针不能比较，否则行为未定义，参见 ISO C11 6.5.8 和 ISO C11 J.2 。另见 https://www.securecoding.cert.org/confluence/display/seccode/ARR36-C.+Do+not+subtract+or+compare+two+pointers+that+do+not+refer+to+the+same+array 。
在 ISO C++ 中，上述限制不适用，结果可能未指定但不引起未定义行为，参见 ISO C++11 5.9 。
作为限定符相关的指针比较操作问题 [CWG 73, CWG 1512] 的解决， ISO C++ 进一步保证对关系操作中蕴含的相等的比较，结果是确定的 [WG21 N3478, WG21 N3690]。

@5.2.7 程序的启动和终止：
ISO C++ 规定程序必须包含全局 main 函数。在独立实现中，是否需要定义 main 函数由实现定义。
main 函数被作为程序的入口。 ISO C++ 规定 main 函数必须返回 int 。只有两种形式的 main 函数总是被实现支持。
在 main 函数中省略 return ，默认同 return 0 。
任何需要其它形式实现支持的入口需提供文档说明。
ISO C++ 规定 main 函数不能被使用：不能被递归调用。
程序在入口结束时或被特定的库函数(@5.15.3.4) 终止。
注意非正常终止程序不保证析构函数被调用，可能导致非预期的行为。
任何终止程序的行为需提供文档说明。

@5.3 词法、预处理和内容无关的上下文编码规则：
本节以外其它相关编码风格参见 @6 。

@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 查找关联名称为空。
不使用冗余的限定名（如非模板类型参数相关且 ADL 和非限定名称查找结果一致时），但需要突出所在的作用域时除外（例如使用带有前缀 :: 的全局名称以便和其它命名空间的名称区分）。

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

@5.3.3.3 类作用域：
基本内容参见 ISO C++11 3.3.7 。
注意类作用域内声明的名称的作用域不仅仅从声明点到类定义结束，还包括所有函数体、默认参数、异常规范和初值符。
类定义内的名称必须指称相同的声明，且调整成员声明顺序不改变这些指称，否则程序形式非法但不要求诊断(@5.1.8) 。

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

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

@5.3.5 宏定义：
有源代码兼容性和可读性良好替代方案的情况下，尽可能不使用宏。
在不能确定特定宏未被定义时，为避免重复定义，在定义前应使用 #undef 或条件包含判断宏是否需要定义。
注意保留名称规则(@5.15.1.2) 也适用于宏。

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

@5.3.5.2
某些宏影响实现特性的宏，如 __STRICT_ANSI__ 或 _POSIX_SOURCE 。注意应在标准库头前包含之前决定唯一定义。

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

@5.3.7
可以使用 #error 和 #line ，但没有确定环境支持时，仅使用基本字符集的字符，以免出现不符合的预期文本。
对 #error 提示用户的文本内容，一般尽量使用字符串字面量而不是直接的记号序列，以完整地表达含义且便于搜索。
在确定环境支持时，可使用 #warning 。

@5.3.8 #include 指令：
使用 <头名> 或 <相对路径> 表示外部库依赖项（仅允许头）， "文件名" 或 "相对路径" 表示内部库依赖向（特殊情况下允许源文件，但需在文档中说明目的）。
关于搜索路径，另见 @5.1.3.1 。
在非正式测试等临时用途以外的情况下不使用绝对路径。
在翻译单元中一般应保持 #include 指令最前，除以下例外：
需要在特定位置（可能重复）包含；
需要定义影响后继 #include 的宏（如 @5.3.6.2 的情形）。
后者可能被工具链中的预定义宏选项替代。

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

@5.4 替代记号(alternative tokens) 、转义字符序列和字面量：

@5.4.1
一般不使用替代记号，以避免导致被替代的标点不够清晰。

@5.4.1.1 例外：
使用 and 和 or 代替内建操作符 && 和 || 以向读者强调对预期的程序逻辑，两个操作数的求值顺序可被交换（注意 C++ 语义仍然一致）。

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

@5.4.3
关键字 true/false 和 bool 类型对应；宏 TRUE/FALSE 和 int 类型（例如自定义的 BOOL 类型）对应。
除非有必要，仅使用前者。
另见 @5.11.6 。

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

@5.4.5 零值：
除非没有语言特性支持，以下规则不优先于 @5.9.4 。
整数用 0，浮点数用 0.0 。有必要使用 float 时，用 0.F 。
空指针用 nullptr （考虑 C 兼容性可以在保证定义正确的前提下使用 NULL ）。
表示字符串结束的空字符用值初始化的非字面量（对字符类型 T 使用 T() ）或自定义宏 NUL 表示。其它具有零值的字符用对应类型的字面量如 '\0' 或 L'\0' 等表示。
bool 类型以外的整数类型零值和 false 可以互相转换。另见 @5.11.6 。

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

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

@5.5 声明和命名空间：
注意区分涉及声明的语法歧义，参见 ISO C++11 6.8 。
注意函数声明和函数定义的区别。
除了头文件中的函数声明以及其它特别注明外，尽量使用定义代替非定义的声明（如类定义代替类名声明，函数定义代替非函数定义的函数声明）。
不在同一个文件且同一个作用域内使用超过一个等价的声明。

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

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

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

@5.5.4 static 和 thread_local ：

@5.5.4.1 命名空间作用域 static ：
注意命名空间作用域的 static 修饰的声明的名称具有内部链接。
避免使用 static 在命名空间作用域声明对象，参见 @5.1.6 以及以下讨论；除非明确需要内部链接且使名称满足特定于实现的需求。
使用翻译单元内的适当的若干未命名命名空间代替，以便自由选择使用内部链接或外部链接，且允许使链接作用于类类型或 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.8) 时不需要定义。这是初始化且不引入定义的唯一特例（关于声明和定义，参见 ISO C++ 3.1 ）。

@5.5.4.3 块作用域 static ：
注意块作用域 static 用于修饰声明的对象，决定其具有静态存储期。
除非有明确目的，使用 static 保证块作用域 const 对象不占据多余的存储，参见 ISO C++11 [intro.object]/6 和 CWG 734 ；另见 https://llvm.org/bugs/show_bug.cgi?id=27443 。

@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 。
仅在命名空间作用域中使用显式 extern 声明。

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

@5.5.5.3 语言链接(language linkage) ：
ISO C++ 指定实现需要支持 extern "C" （ C 语言链接）和 extern "C++" （ C++ 语言链接），默认隐式为后者。
特定的 C++ 语言构造要求使用 C 语言链接（如 @5.15.3.2.3 ）。除此之外，使用 C 语言链接以兼容 C 实现，并在 C++ 实现之间的互操作时取得一般较好的兼容性。

@5.5.6 inline 和 constexpr ：
注意 constexpr 隐含 inline 。
inline 对 namespace 的使用参见 @5.5.8.3 。

@5.5.6.1 语法：
在必要时使用 inline 关键字。
类定义内不使用冗余的 inline （类模板的成员不适用）。
使用 static inline 而不是 inline static ，使用 thread_local inline 而不是 inline thread_local ；原因参见 @5.5.4.5 。
保持和 static inline 风格一致性，一般使用 explicit inline ，而不是 inline explicit （但和 https://github.com/cplusplus/draft/issues/119 不同）。
friend 及修饰整个声明的属性（如 [[noreturn]] ）和 explicit 类似。
constexpr 及表示链接的扩展标签和其它关键字连用的顺序和 inline 类似。

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

@5.5.6.3 禁止内联：
需要保证函数定义在确定的翻译单元时，应避免内联，首先不在公用头文件中使用 inline 修饰函数声明，并避免在类定义内定义成员函数。
对模板实例，使用显式实例化和 extern 声明保证。
必要时使用实现的扩展禁止内联。
以下情形应考虑避免内联：
典型实现的虚析构函数的符号位置可能影响虚表的位置（若所有虚函数定义通过 #include 指令引入，则在每个翻译单元生成虚表： Clang++ 警告 [-Wweak-vtables] ）。需要确保符号唯一时，至少一个虚函数（通常是虚析构函数）应仅在类中声明，而定义在确定的翻译单元中（通常非头文件），即使使用显式默认的析构函数。
作为公开接口的回调函数在库中应保留明确的定义以便确定唯一实体。对动态库，应避免实现自动导入或其它修饰。

@5.5.6.3 链接：
注意函数上的 inline 和链接是正交的。注意具有外部函数的 inline 函数需要避免引用函数外定义的同名的不同实体，除非仅限非 odr-used 其值，以避免违反 ODR 造成未定义行为。
在此基础上，不连用 static inline ，以在未命名命名空间中的 inline 代替，即不直接使用 static 声明内部链接(@5.5.4) 的 inline 函数。
为避免未定义行为，同时禁止 ord-used 外部具有内部链接的变量（例如非 extern 的 const 或 constexpr 声明的对象）。
注意调用函数参数对此的 odr-used ，避免初始化引用类型的形式参数（包括使用 && 推导类型，参见 @5.7.10 ）。另见 @5.12.2.1 。

@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 typedef 和 using ：
不使用 typedef ，使用 using 别名声明代替。
注意 using 声明优先于 using 指令。
在 using 指令引入同名声明指称不同实体而造成歧义时，可使用适当的 using 声明消除歧义。
注意只使用 using 声明可能歧义的名称之一，否则仍然会造成歧义。具体选择应考虑语义、可转换性和用户代码的适配难度。

@5.5.7.1 using 声明：
不使用冗余的 using 声明。
尽量避免在命名空间作用域内，尤其是头文件中使用 using 声明，以防名称污染。
在类作用域内合理使用 using 声明使被隐藏成员可见，或避免声明同名重载函数隐藏基类的同名函数成员。此时需要注意访问权限控制(@5.13.5) 。
注意类作用域内使用的 using 声明和构造函数/模板继承语法相似但语义不同。
类作用域内使用 using 声明应直接使用被声明的成员所在的直接或间接基类以便找到原始成员声明，除非至少存在以下情况之一：
需要避免多个基类声明路径不唯一造成歧义；
需要强调作为公开接口的 using 声明不依赖引入这个成员的所在的类而是其派生类。

@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 中未命名命名空间具有外部链接，但可能被实现优化，如 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21581 。
注意 ISO C++11 3.5/4 明确，未命名命名空间及其中直接或间接的命名空间具有内部链接。
根据 @5.5.8 讨论的规则，未命名命名空间中的名称具有内部链接。

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

@5.5.8.3 内联命名空间(inline namespace) ：
在 ISO C++11 实现及启用某些扩展的实现（如 Clang++ ）中，可在命名空间定义(namespace-definition) 中使用 inline ，可用于区分版本等。
和函数不同，对命名空间声明，可以只在原始命名空间定义（ original-namespace-definition ，之前未存在其它定义）中使用，而不需要所有声明都指定 inline 。
只要能确定命名空间定义在翻译单元中是原始命名空间定义，其它同一命名空间的定义（ extension-namespace-definition ，扩展命名空间定义）中的 inline 冗余使用并非语言规则强制必要；但一般仍应使用 inline 清楚地表示 inline 命名空间。（已知 Clang++ 3.4 (trunk186265) 默认会对不使用 inline 的情况产生警告。）
注意 ISO C++ 要求若在定义中使用 inline ，则必须是原始命名空间定义。实现可能不严格检查（如 G++ 和 libstdc++ 的 bug ： http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53402 ）。

@5.5.9 友元：
禁止在类定义中定义友元类。
注意声明在类的友元在命名空间中不自动可见。
注意友元函数非成员函数。
除了以下提及的用法，避免使用友元。

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

@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.5.11 属性(attributes) ：
按需使用属性。在实现支持时可以使用扩展，如 GNU C++ 的 __attribute__ 和 Microsoft VC++ 的 __declspec ，并考虑用宏统一包装。
注意 ISO C++ 的属性被设计为尽量减少语义的改变，参见 http://herbsutter.com/2012/04/05/reader-qa-what-does-it-mean-for-attributes-to-affect-language-semantics/ 。
属性可以修饰声明或声明符。若两者效果等价（如 [[noreturn]](@5.5.11.1) 修饰函数声明），当声明中只有一个声明符时，直接使用声明的属性而不是声明符的属性。
注意 ISO C++ 属性和扩展不一定通用。如 [[noreturn]] 不支持修饰 lambda 表达式（尽管 G++ 错误接受，但 Clang++ 拒绝），而 __attribute__((noreturn)) 可用。
另见 @5.5.6.1 。

@5.5.11.1 [[noreturn]] ：
注意一个翻译单元中 [[noreturn]] 如在函数声明中出现，则每一个函数声明中都必须出现，否则程序形式非法但不要求诊断(@5.1.7) 。
注意若从 [[noreturn]] 返回则行为未定义。
作为程序出口的函数可以直接捕获所有异常以改变运行时行为。

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

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

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

@5.6.3 例外：
在函数参数列表中，省略不直接修饰参数的 const 。
在异常捕获块和异常规范中，省略形式参数顶层的 const 和 volatile 修饰符。
函数参数类型在语义上必要时，考虑不使用 const ，参见 @5.12.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 。
除了 char 以外的内建字符类型关键字在位域外不需要被 signed 或 unsigned 修饰。

@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 具有相同的大小和对齐要求，但是三种不同的类型。
注意 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.7.9 auto 和 decltype ：
auto 使用模板推导规则。另见 @5.5.1 。
一般应尽量使用 auto （以及 auto& 或 auto&& ）合理缩减声明类型的复杂性，但当类型关键字能够被确定且不超过 4 个字符（即不长于 auto ）时直接使用类型名称而不是 auto 。
注意 decltype 结果与操作数是否为 id-expression 和是否带括号相关。
注意 C++14 的 decltype(auto) 和 C++11 auto 的差异。

@5.7.10
注意 && 模板参数的特殊性。模板实例可能对应左值或右值类型。
另见 @5.2.4.2 。

@5.8 操作符、内建操作和常量表达式(constant-expression) ：

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

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

@5.8.3 自增和自减：
注意前置自增/自减和赋值的等价性。
注意后置自增/自减的副作用。

@5.8.4 sizeof 、 alignof 和 alignas ：
注意 ISO C++ 的 sizeof 、 alignof 和 alignas 的表达式是静态求值的常量表达式(@5.8.11)，它们的操作数是非求值操作数(@5.2.6) 。
注意 ISO C99 引入的 VLA 的数组类型 sizeof 在运行时求值，但 ISO C++ Array TS 引入的运行时确定的数组类型禁止使用 sizeof ，因此 sizeof 可确定是静态求值的常量表达式。

@5.8.5 new/delete 表达式：
注意 new 和 delete 匹配， new[] 和 delete[] 匹配，否则行为未定义。
注意 placement new 和（类类型的）析构函数匹配。
注意 new/new[] 失败时可能由 operator new 或构造函数抛出异常。
除非是对内置类型非静态数据成员的明确默认初始化（即不初始化）， new 必须初始化（即对类类型也使用“ () ”而非省略）。
注意不同 new 表达式之间没有特殊规则保证副作用发生的顺序(@5.1.11.3) ，参见 CWG 130 。
优先使用智能指针(@5.15.9) 代替直接使用 new/delete 表达式分配和释放资源。后者仅用于特定实现（如智能指针或分配器）或当无法在所有条件编译场合下能简洁一致地使用前者时。可以在所有权明确转移时使用 new 表达式，如 @5.15.9.2 。

@5.8.6 显式类型转换：
参见 @5.11.4 。

@5.8.7 typeid ：
注意 typeid 的操作数是非求值操作数(@5.2.6) 。
注意 typeid 对非多态类参数静态求值，而对多态类参数在运行时确定动态类型，有一定运行时开销，且根据 ISO TR 18015 可能较 dynamic_cast 更难被实现优化。
另见 @5.11.4 。

@5.8.8 算术操作、逻辑操作和位操作：

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

@5.8.8.2 溢出：
注意有符号数溢出是未定义行为。
四则运算、取余和向左移位均可能导致溢出。
除数为 -1 可导致溢出，如 http://kqueue.org/blog/2012/12/31/idiv-dos/ 。
注意 n 位无符号数的内建二元 + 、二元 - 、 * 、 ++ 、 -- 、 << 及对应复合赋值和一元 - 操作遵循模算术(modular arithmetic) ，保证不溢出而保证结果回绕为 2 ^ n 的余数。
应特别注意避免无符号数减法导致非预期的结果。参考： https://www.securecoding.cert.org/confluence/display/seccode/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap 。

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

@5.8.8.4 逻辑操作：
注意内建 && 和 || 的短路求值：在第一操作数满足条件时不对第二操作数求值。注意重载的 && 和 || 没有这个性质(@5.12.3) 。
另见 @5.4.1.1 。

@5.8.8.5 移位操作：
注意右移位时从高位填充 0 或 1 （实现为算术右移或逻辑右移）由实现定义。
另见 @5.8.3.2 。

@5.8.8.6 其它二元逻辑操作：
注意 & 、 | 和 ^ 的优先级。
注意 & 和 | 没有类似 && 和 || 的短路求值(@5.8.8.4) 。

@5.8.9 赋值表达式：
包括简单赋值表达式和复合赋值表达式，后者通过前者明确定义。
赋值操作的副作用在 ISO C11/ISO C++11 被更严格地限定顺序。
注意存在一些表达式在 ISO C90/99 和 ISO C++98/03 中存在未定义行为，但在 ISO C11 和 ISO C++11 正确的表达式如 i = ++i （另见 @5.8.3 ）。

@5.8.10 条件表达式：
注意条件表达式对值类别(@5.2.3) 的要求和影响。
注意 ISO C 和 ISO C++ 的条件表达式的语法差异。

@5.8.11 常量表达式：
特定的表达式可以在翻译时静态求值。
注意一些字面量、 const 修饰类型的特定表达式，以及 constexpr 决定的表达式是常量表达式。
注意超过实现限制的表达式不是常量表达式。
注意未指定行为，如浮点计算精度导致某些表达式不能作为可移植的常量表达式。

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

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

@5.9.2 直接初始化(direct initialization) 和复制(copy initialization) 初始化。
注意引起初始化特定的语法形式，区分直接初始化和复制初始化。
特定的上下文的初始化，如传递参数，总是复制初始化。
其它上下文中，用户声明变量或 new 语句中可以不同形式的语法指定不同的初始化。
复制初始化要求对象类型可被复制构造。注意对非 trivally copyable 类型直接初始化和复制初始化的行为可能不同。在这些情况下不使用复制初始化。
其它语法使用规则参见 @5.9.2.2 。

@5.9.2.1 歧义：
注意“ () ”形式的直接初始化受限。
声明对象时的初始化列表必须非空且其参数不能是类型名的函数风格转换，否则会被解析为函数声明符的组成部分而不是初值符，参见 ISO C++ 8.2 。另见 @5.10 。

@5.9.2.2 语法使用：
按是否允许“ () ”形式的直接初始化规则分为两类。

@5.9.2.2.1 直接初始化优先：
除规则 @5.9.2.1 和 @5.9.4 更优先外，以下上下文中尽量使用“ () ”形式进行直接初始化。
适用于允许进行“ () ”形式的直接初始化的上下文，包括：
compound-statement 和 for-init-statement 中声明变量时的 initializer ；
new-expression 中的 new-initializer ；
lambda-expression 内的 lambda-introducer 内 lambda-init 中的 initializer （ ISO C++14 起）。

@5.9.2.2.2 复制初始化优先：
对类类型以及不能排除是类类型的（如带有模板参数的）依赖类型的对象，尽量使用直接初始化以避免可能的复制开销；否则使用复制初始化。
注意在此 ISO C++11 也支持列表形式的直接初始化（“ {} ”）。
适用于“ = ”起始的复制初始化，但不支持“ () ”形式的直接初始化的上下文，包括：
selection-statement 的 condition 内的初始化，包括 if 和 switch 语句的条件；
iteration-statement 的 condition 内的初始化，包括 while 和 do-while 的条件以及 for 语句的可选条件；
member-declarator 的可选 brace-or-equal-initializer ，即类定义内的成员初始化（ ISO C++11 起）。

@5.9.3 零初始化(zero-initialization)  、默认初始化(default-initialization) 和值初始化(value-initialization) ：
注意静态或线程存储期的对象被零初始化。
注意 ISO C++11 明确默认初始化允许不进行初始化。此行为和 ISO C 兼容。
注意 C++14 由于 CWG 1301 的解决，明确显式默认的默认构造函数(= default) 和显式删除的默认构造函数 (= delete) 或用户提供(user-provided) 的构造函数不同。

@5.9.4 初值符(initializer) 、聚集(aggregates) 、列表初始化(list-initialization) 和初始化列表(initializer-list) ：
合理使用类似语法。聚集类型需要和 C 兼容（如原子类型）时，使用复制初始化，否则适用以下规则。
不引起含义改变时，使用 {} 代替较长的默认值，如 nullptr 或 false ，而不代替 0U 等。
不引起含义改变时，使用 {} 代替较长的初值符（ *-initializer ），如 nullptr 或 false ，而不代替 (0) 等。另见 @5.9.2.1 。
不引起含义改变时，使用 {} 代替表示空字符串的字符串字面量如 "" 。

@5.9.4.1 列表初始化：
注意初值符的表达式有特定规则确定求值顺序(@5.1.11.3) ，参见 CWG 1030 。
注意 C++14 由于 CWG 1301 的解决优先对聚集进行初始化，和 ISO C++11 的顺序不同。

@5.10 语句和控制流：
编码时应注意避免干扰实现的分支预测优化。必要时可使用经过包装的特定实现的扩展。
语句中允许声明变量并初始化。初始化相关的语法使用规则参见 @5.9.2 。

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

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

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

@5.10.4 for 语句：

@5.10.4.1 for-init-statement 和 condition 子句：
注意 for-init-statement 必须存在，而 condition 是可选的。
使用的初始化语法规则不同，参见 @5.9.2.2 。

@5.10.4.2 expression 子句：
注意 expression 是可选的。
关于迭代条件的使用要点，参见 @5.8.3 和 @5.12.3.3 。

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

@5.10.5 异常使用规则：
理解 C++ 语言提供的异常是同步异常，此外存在体系结构和其它非同步异常，可能表示程序的设计和实现错误或非预期的运行环境，不由 C++ 异常处理机制解决。
理解 C++ 语言提供的异常机制及实现的限制，参见 @5.14 。
在必要时使用异常，而不是错误码或其它替代手段。
对通用的接口，可以同时保留使用异常和错误码表示错误的版本。
用于表示正常流程结果不使用异常，使用返回值等其它手段。
在大的循环内部或立即需要处理错误时不使用异常以保持代码清晰及减少不必要的性能开销。
除非必要，不使用嵌套 try 块。
除以下例外，禁止使用 catch(...) 捕获所有异常而不重新抛出（除非保证程序控制流不到达或另行约定，此情况需要记录运行时日志），以免未预期地捕获非 C++ 异常(@5.14.2.2) ：
预期程序退出（包括记录致命错误的日志程序、 @5.5.11.1 以及 @5.15.3.3 的情形）但最终抛出异常时；
在析构函数边界根据语义要求捕获异常，参见 @5.13.4.4 ；
特定运行时程序边界抛出其它异常，且明确约定允许捕获非 C++ 异常时；
全局 main 或线程启动函数需要无异常退出以保证程序继续运行时；
使用 std::make_exception_ptr 或特定实现的异常传播机制保存异常；
另行约定的情形。

@5.10.5.1 异常安全(exception safety) 约定：
基本内容参见 http://www.boost.org/community/exception_safety.html 。
可能在以上模型中插入其它层次，如 http://www.reddit.com/r/haskell/comments/2mfxka/handling_async_exceptions_in_haskell_the_right_way 。但为简化问题和特定语言上的解，在通用需求上只考虑此模型。
外部代码和非外部代码的约定不完全相同。外部代码指当前程序组件的外部实现([Documentation::ProjectRuls @@3]) 代码。

@5.10.5.1.1 基本异常安全(basic exception safety) 保证：
除非另行约定，总是需要保证的最低安全性：避免异常处理造成资源泄露。

@5.10.5.1.2 强异常安全(strong exception safety) 保证：
必要时实现抛出异常后的状态回滚。

@5.10.5.1.3 无异常抛出(no-throw) 保证：
必要时使用，禁止异常导致控制流中断。

@5.10.5.1.4 资源生存期、资源类和资源对象：
优先使用 RAII 和确定性析构的 RRID[Documentation::CommonRules @@2.3.2.3] 实现异常安全的设计，封装资源为资源类：使用构造函数获取资源，使用具有无异常抛出保证(@5.10.5.1.3) 的析构函数释放资源。
资源类的对象是资源对象。资源对象的析构函数不应包含清理和释放资源以外的逻辑。
资源类的析构函数具有释放语义，需提供无异常抛出保证(@5.10.5.1.3) ，或在失败时终止程序(@5.2.7) 。
任何可能允许异常抛出的清理操作需要另行公开，在析构函数中调用并处理（忽略或进行无异常抛出保证的日志记录操作等）。
另见 @5.13.4.4 。

@5.10.5.1.5 提交(commit) 操作：
提交操作保存状态。除非能立即处理异常，保证异常中立(@5.10.5.2) ，允许异常传播。
析构函数可能进行提交操作，此时不需要提供无异常抛出保证(@5.10.5.1.3) ，参见 @5.13.4.4 。

@5.10.5.1.6 基本例外：
用于实现保证异常安全的资源管理的分配([Documentation::CommonRules @@2.3.2.3]) 相关例程（如 ISO C++ 约定的存储分配函数），处理的资源本身不保证异常安全，包括：
分配例程的直接调用；
对应的实现例程（如 std::malloc 可用于实现 ::operator new ）的调用；
包装分配例程的直接调用（如分配器的分配方法）。
这些例程的实现本身仍应该保证基本异常安全，即保证不泄漏正在分配以外的资源。
除 ISO C++ 分配例程（重载或替换 operator new 和 operator new[]），使用基本例外的例程仍应在文档说明。

@5.10.5.1.7 外部代码约定：
若声称提供异常安全保证的代码允许控制流转移到外部实现（如回调），则实际的异常安全受到外部实现的代码限制，为其中较弱的一个。
除非另行约定，总是要求外部代码（至少）满足基本异常安全保证(@5.10.5.1.1) 。

@5.10.5.2 异常中立：
除非属于内部实现或异常能够被合适地完全处理，或应当保证异常不被传播(@5.10.5.1.3) ，总是向调用者重新抛出捕获的异常。
除非必要（如保证异常不被传播(@5.10.5.1.4) ），尽量保持异常中立。

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

@5.10.5.4 异常类：
避免抛出非类类型异常以便捕获抛出的异常对象。

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

@5.10.5.4.2 异常类成员：
考虑避免可能在构造函数时抛出异常的成员，这可能会直接导致无法捕获预期类型的异常对象。
必要时，格式化 what() 或其它成员的输出信息。

@5.10.5.5 异常规范：
除了本节指出的例外，在无异常抛出保证[Documentation::CommonRules @@3.6.2.1.3] 的场合，应使用异常规范。
在非显式使用的异常规范上下文中，使用自定义的异常规范宏代替 throw 关键字。
注意动态异常规范是 ISO C++11 中的 deprecated 特性(@5.1.6) ，应限制使用（如仅用于调试）。
除异常类设计和本节提到的其它例外，不显式地使用异常规范，而用异常规范宏代替。
注意 ISO C++11 规定的继承构造函数/模板和特殊成员函数的隐式异常规范。除析构函数外，只在必要时使用推断的隐式异常规范，否则应显式在声明中指出。
注意覆盖虚函数的异常规范至少和被覆盖的虚函数一样严格。除非确定不覆盖（如作为 final 类或至少不使用 public 继承），析构函数一般不显式使用异常规范。
注意按 WG21 N3279 ， ISO C++ 标准库实践中析构函数不使用异常规范，如 WG21 N3508 ；但按 ISO C++ 15.4/14 析构函数上隐式的异常规范同隐式声明的特殊成员函数而不是无条件地默认 noexcept （如 [WG21 N3166] 的提议）。
注意隐式推导同特殊成员函数。当定义中有 throw 表达式时不自动推导为隐式异常，允许抛出异常时需要显式指定异常规范。
注意不同配置下的不同表达式调用对析构函数隐式异常规范推导的影响，如断言(@5.15.3.3) 在析构函数中使用时应始终保证无异常抛出。

@5.10.5.5.1 noexcept 使用准则：
使用 noexcept 代替 noexcept(true) 。
注意违反 noexcept 可能导致程序非正常退出。
注意 WG21 N3248 明确了标准库使用 noexcept 的准则。
为了便于程序验证（可测试机性等），不直接在所有无异常抛出保证的函数上使用 noexcept ，仅当函数具有 wide contract([WG21 N3248]) ，即保证不（因为参数或状态违反前置条件）引起未定义行为时使用 noexcept 。
WG21 N3263 在此基础上明确了标准库容器(@5.15.11) 成员的 noexcept 使用。 WG21 N3279 明确了标准库中的一般使用。
转移构造函数、转移赋值函数和 swap 需要使用 noexcept ，除非依赖于仅由模板参数引入的对应操作非 noexcept 的基类或成员子对象。
除以下指定的规则外，一般库的设计应遵循标准库上述对异常规范的使用准则。
资源对象(@5.10.5.1.4) 的析构函数需要保证无异常抛出时不使用允许抛出异常的异常规范。注意隐式推导时调用的函数需要保证具有无异常抛出保证的异常规范。
仅在隐式异常规范不符合接口目的时使用 noexcept 指定不同行为。
以下情形的任意其它析构函数允许显式指定 noexcept 异常规范，但需要在文档中标注并明确理由：
禁止抛出异常：保证不抛出异常，但隐式异常规范不保证无异常抛出；
允许抛出异常：明确保证不在栈展开(@5.14.1) 时使用，明确允许抛出异常，但隐式异常规范保证无异常抛出；
允许可能抛出异常：使用 noexcept 的操作数指定可能抛出异常，一般用于模板代码。

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

@5.11 标准转换、显式转换和类型使用限制：

@5.11.1 左值变换(lvalue transformation) ：
讨论重载(@5.12.1) 时，标准转换 lvalue-to-rvalue conversion 、 array-to-pointer conversion 和 function-to-pointer conversion 统称为左值变换。
注意函数参数和返回类型的退化(decaying) ：数组到指针，函数到函数指针。
可以使用 std::decay 显式实现。

@5.11.2 非确定长度的数组：
除非兼容性需要，不使用非确定长度的数组（包括扩展的变长数组）。

@5.11.3 显式类型转换：
使用 C++ 风格而不是 C 风格的显式类型转换。
足够清晰时使用 C++ 类构造函数语法代替 reinterpret_cast 和 static_cast 而不使用显式转换，以避免过于冗长。
优先使用函数模板包装转换以明确更特定的语用。

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

@5.11.5
除非显式约定布局，禁止对派生类的成员指针使用转换为基类成员指针的 static_cast ，以避免成员指针实现相关的错误。

@5.11.6 转换为 bool ：
注意 if 的条件表达式等上下文遵循 ISO C++11 的 contextually converted to bool ，此时无需转换。尽量使用此规则保证相关上下文中的无歧义和简洁。
注意 ISO C 的对应上下文中不使用此转换。
例如对指针类型 p ，在 C++ 中使用 if(p) ，在 C 中使用 if(p) 或 if(p == NULL) （而 if((int)p) 不保证等价）。
注意浮点数等允许通过标准布尔转换隐式转换为 bool 类型。
另见 @5.12.1 。

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

@5.12.1 函数重载：
避免不必要的重载和歧义。
重载使用复杂的规则。注意 explicit 关键字对重载的影响。
对不期望隐式转换的类类型，使用 ISO C++11 引入的 explicit 转换操作符避免不必要的转换；在 ISO C++98/03 中使用转换为非公开成员指针类型代替。
注意函数和返回类型的限定符(@5.6) 和退化(@5.11.1) 不影响函数类型等价性。

@5.12.2 参数和返回：
除非以下讨论的语义上的必要性，不使用 const 左值引用类型以外的参数类型。另见 @5.12.1 。
参数类型和返回类型使用单一的 void ，但不能被限定符(@5.6) 修饰。
在需要完全的值类型语义且复制开销较小（例如传递一个内建整数类型的对象、内建指针、典型的迭代器、常见的函数对象）时，使用非引用类型形式参数或返回类型。
对直接按值复制传递的函数参数，当需要按引用传递时，使用 std::ref 或 std::cref 包装。
（经验表明特定布局的非空类类型的小对象使用 const 左值引用可提供比直接使用对象更多的优化机会，例如包装整数类型的 union 在 G++ 4.7 上的表现。）
注意参数传递和返回值初始化是复制初始化，可能调用复制构造或转移构造函数，可能有复制省略，参见 @5.13.4.3 。

@5.12.2.1 参数类型：
注意只有没有参数的函数允许使用 void 参数类型，在 C++ 中一般省略。
注意非定义的函数声明中 C 和 C++ 对空参数列表的不同： C 的“ () ”相当于 C++ 的“ (...) ”，而 C 的“ (void) ”相当于 C++ 的“ () ”。
函数定义中 C 的“ () ”和 C++ 相同，但一般和原型声明保持一致以保持清晰。
在需要转移语义(@5.2.4.1) 时，使用非 const 右值引用类型参数，同时使用 std::move 或等价的显式类型转换包装参数传递。
当使用类的静态对象作为默认参数时，引用类型的形式参数造成此静态对象的 odr-used (@5.1.8) 因此需要额外的类外定义（参见 @5.5.4.2 ），即便是 const 或 constexpr 决定的常量表达式(@5.8.11) 。
复制开销可预测且不需要修改参数时，以下情形为直接使用对象类型而非其引用类型作为参数：
不显式指定布局的类型；
在一般体系结构可能具有较大复制开销的类型；
仅需要常量表达式的值，保证使用 lvalue-to-rvalue conversion (@5.11.1) 的结果，为了省略前述的静态数据成员定义时。

@5.12.2.2 返回类型和返回值：
除了 @5.12.2 的约定外，当返回对象可转移构造时，返回类型也可使用直接使用对象类型。
另见 @5.13.4.3 。

@5.12.2.3 参数传递：
仅向内部实现中的调用传递参数，外层参数使用非 const 右值引用类型时，同时使用 std::forward 或等价的显式类型转换包装参数传递。
注意右值对象引用类型的参数不保证实际参数在函数调用后被转移(@5.2.4.1) 。
对可转移构造但不能复制构造的对象类型非模板函数参数，仅当可预期和可接受转移构造开销并且总是需要转移操作时直接使用对象类型，否则使用右值引用参数。参见 http://scottmeyers.blogspot.com/2014/07/should-move-only-types-ever-be-passed.html 的讨论。
另见 @5.2.4.1 和 @5.15.9 。

@5.12.2.3.1 例外：
可另行约定特定对象类型对应的右值引用类型参数可不被认为引用唯一对象且不保证被转移。
这表示这些函数的实现不能假定实际上引用的一个对象类型右值而不是经过显式转换为 xvalue 的左值，因此不能随意进行别名优化；同时，转移后的对象必须具有确定的状态。
实用意义上，这里使用右值引用主要原因为允许直接构造临时对象作为函数的实际参数，而不是为了启用使用转移语义(@5.2.4.1) 的优化。

@5.12.3 操作符重载：
对一元操作符重载，使用成员重载。
对参数形式对称的二元操作符重载，使用非成员重载并合理利用转换。
注意重载的操作符如 = 、 && 、 || 和 , ，没有和内建操作符相同的操作数值类别限制和求值顺序保证。

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

@5.12.3.2 重载 operator= ：
注意 operator= 被派生类隐藏。

@5.12.3.2.1 特殊成员函数：
注意复制赋值函数和转移赋值函数是非模板的特殊成员函数，实现提供隐式的声明和定义，可以声明为 = default 显式使用（当不满足特定条件时同 = delete ）。
若没有 trivial 复制赋值，没有转移赋值会导致以此类对象作为成员的类无法使用默认生成转移赋值（隐式地，或声明为 = default ，都相当于 = delete ）。
除非另行约定，不应依赖转移赋值不引起实际参数状态的改变。
若转移赋值是必要的，一般应确保存在可访问的转移构造函数。
为避免混淆，一般仅使用特殊成员函数定义的赋值操作。
另见 @5.10.5.5 。

@5.12.3.2.2 自赋值(self-assignment) ：
对参数指定的对象和 *this 相同的情形称为自赋值。
为避免混淆，禁止特殊成员函数以外的自赋值。
根据 @5.2.4.1 指定右值引用参数遵循标准库的约定，除非另行约定，不考虑自赋值。

@5.12.3.2.3 异常：
经典复制赋值实现使用 copy-and-swap idiom 和 const 左值引用参数，能避免自赋值副作用且至少具有强异常安全保证(@5.10.5.1.2) 。
转移赋值一般应保证无异常抛出(@5.10.5.1.3) 。
由于异常规范仅适用于块，不涉及参数复制的异常，因此当函数体内保证无异常抛出时，可以直接使用无异常抛出保证的异常规范。

@5.12.3.2.3 合一赋值(unifying assignment) ：
通过使用非引用参数代替 const 左值引用的 operator= ，称为合一赋值，可以获得对象复制的优化，但具有以下缺点：
重载右值引用参数的 operator= 会引起重载歧义，即无法通过单独重载优化的转移赋值（对转移赋值，使用 copy-and-swap 需要多一步复制/转移构造）；
无条件复制，无法根据被复制的对象的状态进行优化；
因此，除非被复制的对象具有完全的（所有子对象均满足）值语义，一般不重载非引用参数的 operator= ，而分别重载 const 左值引用参数和非 const 右值引用参数的版本（也可能不需要转移赋值，仅重载前者）。

@5.12.3.2.4 一般实现策略：
对保存存储状态的不完全值语义对象（例如容器），使用最小赋值：在 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.3.6 重载operator new 、 operator new[] 、operator delete 和 opertor delete[] ：
不依赖重载成员 operator new 、 operator new[] 、operator delete 和 opertor delete[] 声明的隐式 static ，显式使用 static 关键字以明示不隐含 this 。

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

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

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

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

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

@5.13.2.1 成员初始化：
注意成员初始化顺序。
除非是对内置类型非静态数据成员的明确默认初始化（即不初始化），每个成员必须初始化（另见 @5.8.5 ）。
注意 ISO C++ 支持成员直接在类定义内初始化。可使用列表初始化或复制初始化，使用的语法和策略同 if 条件中的使用，参见 @5.10.1 。
除了类定义内的初始化外，在构造函数内初始化非静态成员。除非必要，尽量使用直接初始化而不是列表初始化或以赋值代替初始化。

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

@5.13.4 特殊成员函数：
注意排除模板。
区分隐式声明和定义。
注意若用户显式声明的即为非 trivial 的。
注意 ISO C++ 构造函数和析构函数中调用虚函数行为同非虚函数，参见 @5.13.7.1 。这和 Java 、 C# 、 C++/CLI 和早期的非标准 C++ 的类似特性不同。

@5.13.4.1 默认构造函数：
注意默认构造函数可能有默认参数。
默认构造函数被显式默认定义(= default) 时行为和显式删除(= delete) 的直接省略 ctor-initializer 的用户提供的定义不同，后两者可能导致默认初始化不初始化成员，参见 @5.9.3 。

@5.13.4.2 隐式声明：
注意隐式声明的特殊成员函数具有的异常规范。

@5.13.4.3 复制和转移：
注意 ISO C++11 12.8/31 指定的允许复制省略(copy elision) 的特殊规则。
注意 ISO C++11 关于隐式声明复制构造函数和复制赋值操作符的 deprecated 特性。
关于复制赋值/转移赋值，参见 @5.12.3.2 。

@5.13.4.3.1 重载解析：
注意 ISO C++ 11 12.8/32 的两阶段重载解析（优先转移，失败时复制）规则，条件为：
考虑被复制的对象为函数参数名指定后，满足复制省略(@5.13.4.3) 的条件（但不论是否进行），且对象为左值。
注意 ISO C++14 12.8/32 对此进行两点修正：
排除 exception-declaration([CWG 1493]) ；
明确 return 语句后的（可以是 id-expression ）被复制的源对象为需要自动存储的对象或函数及 lambda 表达式的形式参数，允许返回类型和 return 的对象类型不一致([CWG 1579]) 。
因此，对 return 作用的以名称出现的非 volatile 类类型自动对象（除函数和 catch 的参数外），不需要 std::move 即可优先转移，仅当无法转移时复制。
注意源对象不是声明为引用的变量。

@5.13.4.4 析构函数：
多态类应该保证具有虚析构函数以避免通过基类销毁对象时的未定义行为。
析构函数应具有释放语义或提交语义，对应的异常保证满足 @5.10.5.1.4 和 @5.10.5.1.5 之一；除非另行约定，一般类的析构函数的行为同资源类。另见 @5.10.5.5.1 。
一般用例参见 http://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor 。另见 WG21 N3614 。
在需要无异常抛出保证时，在不明确何种异常时可以使用 catch(...) 捕获所有异常，否则在 catch(...) 中断言控制流不可达。
关于析构函数的异常规范，参见 @5.10.5.5 和 @5.10.5.5.1 。

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

@5.13.5.1 隐式访问权限：
注意隐式访问权限： class 默认具有 private ； struct 默认具有 public 。
访问权限控制对大多数成员声明能体现实际语义，因此不依赖隐式访问权限，除了以下例外：
省略成员访问权限：友元声明和 static_assert 声明，对此无论何种访问权限都不显式改变语义，因此这些声明应出现在类定义中的第一个 access-specifier 前；
省略基类访问权限：明确的基类继承，如 struct 元函数([Documentation::CommonRules @@3.10]) 继承或混入操作符模板类继承。

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

@5.13.5.3 非静态数据成员访问权限：
注意显式指定非静态数据成员的访问权限可能影响布局和分配顺序。
ISO C++03 9.2/12 规定不同 asscess-specifier 声明的非静态数据成员所在的地址相对顺序和之间的分配顺序是未指定的，这包括相同的访问权限。
ISO C++11 放宽了语言规则的限制但限制了实现： ISO C++11 9.2/13 规定不同访问权限的非静态数据成员所在的地址相对顺序和之间的分配顺序是未指定的。
此外， ISO C++11 9/7 规定含有不同访问权限的非静态数据成员的类不是标准布局类，因此也不是标准布局类型(@5.2.2) 。

@5.13.6 继承：
尽可能使用组合代替 private 继承，除非需要使用作为基类的特性：
派生类覆盖 private 基类的（纯）虚函数；
using 声明基类的成员；
启用空基类优化。

@5.13.7 虚函数：

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

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

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

@5.14 异常：
对异常的使用参见 @5.10.5 。

@5.14.1 异常机制和处理器函数(@5.15.6) ：
抛出异常时引起栈展开(stack unwinding) 按声明逆序销毁自动对象，若存在析构函数则被执行。
栈展开时若重复抛出异常，则调用 std::terminate 。除非必要（通过文档指定行为），应予以避免。

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

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

@5.14.2.2 其它非 C++ 异常。
避免捕获非 C++ 语言异常，以保证实现行为可预测且易调试。

@5.15 标准库：
本节“实现”指 C++ 核心语言和标准库实现。
本节限定适用于标准库用户，但不适用于实现。
注意 ISO C 和 ISO C++ 的标准库头不保证一定是文件。

@5.15.1 名称使用限制：
除非另行约定，本节中引用的标号分别表示 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 ISO C++ 指定的保留名称：

@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.1.3 ISO C 指定的保留名称：

@5.15.1.3.1 核心语言和兼容性：
ISO C11 6.11 指定的记号禁止被声明或作为宏定义。

@5.15.1.3.2 ISO C 标准库：
ISO C11 7.1.3/1 指定的保留名称被 ISO C++11 覆盖。
按 ISO C11 7.1.3/3 ，禁止 #undef 保留名称。

@5.15.1.4 其它保留名称：

@5.15.1.4.1
除非对应的 C 标准库头未被包含，出现在 ISO C++ Annex C.4 中的 C 标准库名称禁止被声明或作为宏定义。

@5.15.1.4.2 POSIX 保留符号：
关于 POSIX.1-2004 指定保留的符号对应的名称参见 http://pubs.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_02.html 。
对其中依赖头的保留符号，除非对应的头未被包含，对应的名称禁止被声明或作为宏定义。

@5.15.1.4.3 宏名：
保留标识符不应作为宏名被 #define 指令定义。
不应该使用依赖保留操作符作为宏名被替换的结果（如直接出现在 #if 后）。
在预处理指令中检查宏是否被定义不引入保留名称，所以允许引用保留标识符作为 defined 的操作数。

@5.15.2 标准库头：
注意标准库头受到 ISO C++ [using.headers] 的约束。
本节“包含”的含义参见 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> ；
<iotream> 包含 <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.3.2 信号处理：
基本限制参见 @5.1.11.4 。

@5.15.3.2.1 信号：
ISO C 仅要求实现有限的信号，即 SIGABRT 、 SIGFPE 、SIGILL 、SIGINT 、SIGSEGV 和 SIGTERM 。
ISO C++ 没有扩充要求实现支持的信号。除非必要，只使用这些信号。 POSIX 和 SUS 提供若干扩展，优先于具体平台扩展选用。
注意存在无法被捕获或忽略的信号。

@5.15.3.2.2 signal 函数：
ISO C11 规定多线程环境下调用 signal 函数具有未定义行为， ISO C++ 无此限制。 POSIX.1-2004 规定多线程的进程中使用 signal 函数未指定。
signal 函数的行为很大程度依赖实现，可能在同一个系统的不同版本（如 Linux ）中具有不同行为。若需可移植性应避免使用。对符合 POSIX 的平台可以使用 sigaction 代替。

@5.15.3.2.3 C++ 互操作性：
ISO C++ 要求信号处理器(signal handler) 具有 C 语言链接。注意 lambda 表达式转换的函数指针不符合此要求(@5.2.6.1) ，禁止在此使用。
ISO C++ 指定和 C 特性兼容的 POF 以及可以用于信号处理器，此外由实现定义。此处实现定义可能不明确，通过调用不需要具有 C 语言链接或仅使用兼容 C 特性的函数变通。
ISO C++11 显式允许信号处理器使用原子操作。 WG21 N3910 进一步明确这些操作的外延。
禁止在信号处理器中抛出异常。 ISO C++ 特别指出在信号处理器中抛出异常很可能有问题。实际实现支持不同，如 Microsoft Windows 上的 Microsoft VC++ 可以支持而 Linux 上的 G++ 未能完全支持此特性。

@5.15.3.3 断言(assertion) ：
注意断言失败时非正常终止程序(@5.2.7) 。断言失败时可以捕获所有异常以避免对运行时行为的干扰。
注意标准库头 <assert.h> 和 <cassert> 可多次被重复包含，使用 NDEBUG 宏控制启用或禁用断言，参见 ISO C++11 17.6.2.2/2 。
跨翻译单元实例化的模板中使用断言时必须确保不同翻译单元同时启用或禁用断言，以避免违反 ODR(@5.1.8) 。
和静态断言不同，断言不保证翻译时。若有可能，使用静态断言代替断言。

@5.15.3.4 终止程序的函数：
注意 std::exit 、 std::quick_exit 和 std::_Exit 的参数的含义。特别地，这些值在不同平台中实现定义的值可能不同。
注意 std::abort 非正常终止程序(@5.2.7) 。
注意 std::atexit 和 std::at_quick_exit 的最小实现限制，除非必要避免使用。
注意 std::quick_exit 执行时不得引发信号，否则行为未定义。
在无法保证异步安全([Documentation::CommonRules @@3.11.2])的多线程环境中一般无法直接使用 std::atexit 和 std::at_quick_exit 可靠地执行任意清理。
注意 atexit 可能被实现（如 libgcc ）用于清理，如调用析构函数。因此，在无法保证异步安全([Documentation::CommonRules @@3.11.2])的多线程环境中应避免直接使用 std::exit 。
同理，需要避免 std::at_quick_exit 注册的回调引起不适当的状态才可在这些环境使用 std::quick_exit 。

@5.15.4 要求(requirements) ：
基本内容参见 ISO C++11 [requirements] 。
除非另行约定，使用 ISO C++11 [utility.requirements] 中的约定指定对类型的要求。

@5.15.5 可替换实现的接口：
全局函数 operator new 、 operator new[] 、 operator delete 和 operator delete[] 可替换定义。
注意这些函数不能以 inline 修饰，实现可不给出违反此规则的诊断(@5.1.8) 。
注意 ISO C++11 起基本的抛出异常形式的全局 operator new 和全局 operator delete 提供了其它可替换函数的基本功能实现。若替换其中的函数，其它函数的行为也可被影响。
注意 ISO C++11 起允许全局 operator new 抛出 std::bad_alloc 以外的异常。

@5.15.6 处理器函数(handler fucntion) ：
处理器函数是 std 命名空间中以 set_* 和 get_* 为名的函数，提供基本一些例程，和整个标准库的状态相关。
ISO C++11 规定调用这些函数不引起数据竞争。

@5.15.7 共享对象和线程安全性：
注意在不同线程间使用可引入数据竞争的标准库函数的程序行为未定义。
标准库定义的类类型的对象的构造函数调用完成应发生在任何成员函数调用之前。

@5.15.8 类型特征(type traits) ：
类型特征于 ISO C++ TR1 和 ISO C++11 中引入，属于元编程设施。
合理使用类型特征进行关系判断，如 is_same 判断类型相同。
合理使用类型特征进行类型操作，如 std::add_lvalue_reference 可避免泛型代码中出现非法的 void& 。

@5.15.9 智能指针(smart pointer) ：
智能指针于 ISO C++ TR1 和 ISO C++11 中引入，用于管理资源。
由于转移语义， C++11 能引入 std::unique_ptr 取代 C++98/03 的 std::auto_ptr ，避免后者区分转移困难、无法作为容器元素等局限。
仅当需要共享资源时使用 shared_ptr ，否则尽量使用 unique_ptr 。
使用智能指针作为参数时的一般规则参见 http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/ ，但 unique_ptr 除外，另见 @5.12.2.3 。

@5.15.9.1 元素类型：
注意 std::unique_ptr 的析构要求元素是完整的对象类型，而 std::shared_ptr 允许直接使用不完整类型（包括 void ）。

@5.15.9.2 助手函数模板：
特定情形使用 make_* 或用户自定义的类似助手模板创建智能指针：
	使用 std::make_shared 减少分离的内存分配（但注意涉及动态删除器可能会因为 RTTI 使二进制文件体积增大）。
	使用 std::make_shared 和 ISO C++14 引入的 std::make_unique 或其它类似的用户自定义接口而不是直接使用可能抛出异常的无序的(@5.8.5) 的 new 保证异常安全(@5.10.5.1) 。
		若没有 std::make_unique ，自行实现。参见 http://herbsutter.com/gotw/_102/ 。
	注意 std::make_shared 和 std::make_unique 值初始化被指向的对象。若需要其它形式的初始化（如默认初始化或列表初始化），可使用自定义的类似接口。
	若创建 std::unique_ptr 需要自定义删除器，无法使用 std::make_unique ，使用其它用户定义的类似接口或显式初始化 std::unique_ptr 代替。
仅当初始化智能指针不引起分配（如直接使用现有具有所有权的指针值初始化智能指针），或引起的单一分配副作用的顺序确定时，允许直接使用来修改智能指针对象（包括但不限于作为赋值的操作数以及 reset 成员函数的参数）。
创建对象满足上述条件的时，以下情形优先直接使用 new 表达式作为操作数而不是助手函数模板，以在保证代码不冗余时减少额外的对象创建和函数返回，便于调试：
	不需要类似 std::make_shared 的分配行为，用于直接初始化指向非数组类型的智能指针对象，但 ctor-initializer 以外初始化指向数组类型的智能指针，能避免重复指定类型名时除外；
	赋值至智能指针时，优先使用被赋值的智能指针的 reset 成员代替。

@5.15.10 文本和字符串：
明确作为 C 风格字符串的 NTCTS （空字符结尾的字符串）的含义，注意和 C 标准库接口的兼容性。
另见 @5.1.4 。

@5.15.10.1 类模板 std::char_traits ：
注意 char_traits 对模板参数的要求。
对字符串批量操作，除非有更具体的成员函数，优先使用 char_traits 的操作。

@5.15.10.2 类模板 std::basic_string ：
注意 ISO C++11 起禁止使用引用计数实现。
一些实现因为 ABI 兼容问题可能保留旧实现，此时需要变通。如 libstdc++ 5 之前的版本，必要时适当使用 __gnu_cxx::__versa_string 代替，但注意不适用于 std::stringstream 等接口。
注意 ISO C++03 之前 c_str 和 data 的语义差异，在 ISO C++11 中两者等价；注意两者和 operator[] 语义的不同。
当前需要访问 std::basic_string 实例对象 s 中的元素时，仍然依序保持以下兼容性较好、更明确的使用规则：
直接访问元素时，用 s[0] 的形式；
访问需要修改的或非临时的存储，或在模板中和 std::basic_string 以外（不一定是字符串的一般序列）类型兼容时，用 &s[0] 或成员/非成员 begin/end 取迭代器的形式；
对需要另行提供长度的，用 s.data() 的形式；
对不需要另行提供长度的，用 s.c_str() 的形式。

@5.15.10.3 类型 std::string ：
注意 std::basic_string 可以有不同的分配器， std::string 使用默认参数，被异常类等显式依赖，应明确和其它类似类型区分。

@5.15.11 容器：
注意容器对元素的要求。
注意异常安全。保证无异常抛出的成员函数不一定显式使用 noexcept ，参见 @5.10.5.5.1 。
注意容器转移后为有效但未指定状态(@5.2.4.1) 而不保证为空。若需要空容器，先调用 clear() 清空。
若有可能，使用 empty 代替 size 。
若有可能，使用 emplace 代替 insert 。

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

@5.15.12.1 迭代器要求：
注意迭代器要求。
注意 ISO C++ 未完全定义所有相关概念，如 [LWG 2035, LWG 2038] ，应在文档中避免这些概念以及不清晰的表述。
注意 ISO C++ 放宽了原始 SGI 迭代器的部分要求，如随机访问迭代器的 + 和 += 操作的范围检查。
考虑 @5.2.6.2 ，如果泛型算法接口中未明确避免指针（以及类似具有检查要求的迭代器）作为实例，应假定这些附加要求存在。

@5.15.13 算法：
注意部分的算法复杂度和类型满足的要求相关。

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

*/
////

