C++的style guide 来自cs106b
Stanford class style guide C++
Google style guide C++
Google 所有语言 style guide
C++ 特性
C++语言功能
-
与C习惯用法相比,更喜欢C ++习惯用法:由于C ++基于C,因此通常有一种“ C ++方式”来完成给定的任务,也有一种“ C方式”。例如,打印输出的“ C ++方式”是通过输出流cout,而“ C方式”是使用printf。C ++字符串使用string类,旧代码使用C-style 。首选现代C ++方式。
-
for vs while:for当已知重复次数(确定)时使用循环;while当重复次数未知(不确定)时使用循环。
-
在循环中中断和继续:在任何可能的情况下,循环应该以普通的方式构建,具有清晰的循环开始、停止、推进和不中断的循环控制。也就是说,有一些有限的break使用是可以的,或者需要在迭代中退出循环。continue很少使用,通常会使读者感到困惑,最好避免使用。
-
在开关情况下使用跌落(fallthrough):开关情况几乎总是以中断或返回结束,以防止继续进入后续情况。在非常罕见的情况下,你打算失败,添加一个评论,使其清楚。意外的跌落(fallthrough)是许多困难的bug的根源。
-
return statements 虽然允许一个函数有多个return语句,但在大多数情况下,最好是在函数的末尾遍历单个return语句。对于递归基本情况或在函数开始处处理错误来说,早期返回可能是一个清晰的选项。return也可以作为循环退出。然而,在函数中散布其他返回值并不是一个好主意——经验表明,它们会造成不成比例的错误数量。很容易忽略提前返回的情况,错误地认为函数一直运行到最后。
-
Always include {} on control statements:if/else、for、while等语句的正文应该总是用{}包装,并有适当的换行,即使正文只有一行。使用大括号可以防止左图所示的事故。
-
布尔型:布尔表达式容易产生冗余或笨拙的结构。选择简洁直接的替代方案。一个布尔值是true或false,你不需要进一步比较true/false或将一个布尔表达式转换为true/false。
-
使用||,还有!over and、or和not:由于各种主要与国际兼容性有关的原因,c++有两种表示逻辑连接词and、or和not的方式。传统上,运算符&&,||,和!分别用于AND、OR和NOT,且操作符是表示复合布尔值的首选方式。可以用and、or和not来代替,但是这样做是非常不寻常的,而且对于习惯于传统操作符的c++程序员来说有点不和谐。
-
使用error来报告致命的情况:来自Stanford库的error函数可以用来报告带有您的自定义消息的致命错误。使用error比抛出原始c++异常更可取,因为它与调试器和我们的SimpleTest框架配合得很好。
高效
在CS106B中,我们重视数据结构和算法的有效选择,特别是在有显著收益的情况下,但不热衷于微优化,因为这些微优化会使代码变得混乱,而收益很少。
- 更好的BigO类:在实现算法的选项中,通常会选择具有更好大O的算法,即O(NlogN)算法优于二次O(N²)、常数O(1)或对数O(logN)算法优于线性O(N)。
- 根据情况选择最佳性能的ADT:例如,如果您需要对collection执行许多查找操作,那么Set会比Vector更可取,因为它具有高效的contains操作。所有的堆栈/队列操作都是O(1)使堆栈成为一个理想的选择,如果您只在顶部添加/删除,或队列完美,如果您从头部删除和添加在尾部。当您不需要按排序顺序访问元素时,选择HashSet/HashMap而不是Set/Map有一个小小的优势。
- 保存昂贵的调用结果并重用:如果您正在调用一个昂贵的函数并多次使用其结果,则将结果保存在一个变量中,而不必多次调用函数。这种优化在循环体中特别有价值。
- 避免复制大型对象:当传递对象作为参数或从函数返回对象时,必须复制整个对象。复制大型对象(如收集ADTs)的成本可能很高。通过引用传递对象避免这种开销。然后,客户机和函数共享对单个实例的访问。
统一通用代码,避免冗余
当你起草代码时,你可能会发现,当你需要重复执行相同或类似的任务时,你会重复或复制/粘贴代码块。将重复的代码统一到一段可以简化你的设计,并且意味着只需要编写、测试、调试、更新和注释一段代码。
- 分解为helper函数:提取通用代码并移动到helper函数。
- 提取公共代码:从连接的if-else或开关的不同情况提取公共代码。
Function design
一个设计良好的函数具有如下属性:
-
执行一项独立的、连贯的任务。
-
不做太多的工作。
-
不会不必要地与其他函数纠缠在一起。
-
使用参数来实现灵活性/重用(而不是单任务工具)。
-
明确信息in(参数)和out(返回值)之间的关系
-
函数结构:一个过长的函数(比如超过20-30行)非常笨拙,应该分解成更小的子函数。如果你试图描述函数的用途,发现自己经常使用“和”这个词,这可能意味着函数做了太多的事情,应该被细分。
-
值与引用形参:当需要修改传入的形参的值或从函数发送信息时,使用引用形参。不要在不必要或无益的情况下使用引用参数。注意,a、b和c不是下面函数中的引用形参,因为它们不需要是。
-
使用返回值而不是引用’out’形参来实现单值返回:如果一个单值需要从函数返回,使用返回值比使用引用’out’形参更简洁。
-
避免“链接”调用: 即许多函数在一个链中彼此调用而不返回main。下面是有(左)和没有(右)链接的调用流示意图:
-
注解
一定要注意你的最终评论是否符合你的最终结果。
-
文件/类头文件:每个文件都应该有一个概述注释来描述该文件的用途。对于作业,这个标题应该包括你的名字,以及这个文件与作业关系的简要描述。
-
引用源代码:如果你的代码受到外部资源(网页、书籍、其他人等)的重大影响,那么源代码必须被引用。在文件顶部的注释中添加引用。明确说明接受了什么帮助,以及它如何/在哪里影响了你的代码。
-
函数头:每个函数都应该有一个头注释来描述函数的高级行为,以及以下信息:
-
参数/返回:给出进入函数的每个参数的类型和用途,以及返回值的类型和用途。
-
前提/假设:客户应该知道的约束/期望。(“此函数期望文件能够打开以进行读取”)。
-
error:列出函数处理的任何特殊情况或错误条件(例如:"…如果除数为0则抛出错误",或者"…如果单词不存在则返回常量NOT_FOUND ")。
-
内联注释:内联注释应该在代码复杂或异常到足以保证这样解释的地方少用。一个好的经验法则是:解释代码实现了什么,而不是重复代码说了什么。如果代码完成的任务很明显,那么就不用麻烦了。
-
TODO 在提交程序之前,删除程序中的任何// TODO:注释。
-
注释掉的代码:提交带有大量“注释掉”代码的程序被认为是糟糕的风格。在处理程序时注释掉代码是可以的,但如果程序已经完成,而不需要这样的代码,那么就删除它。
-
Doc注释:你可以使用“Doc”样式(/**…/)如果你喜欢,可以使用注释样式,但这个类不需要注释样式。注释使用//或/…*/很好。