《C++编程规范》读书笔记(上)

      项目组一直没有做代码审查,最近有启动这项计划的打算,因此提前复习一下《C++编程规范》,并做一些笔记。我们做任何事通常都先从简单的入手,循序渐进,持续改进,那么做代码审查也不例外,《C++编程规范》又很多,如果一下子突然引入,会对代码编写提出过高的要求,对开发人员的打击比较大,从而可能会影响团队的整个士气,所以我想我们应该从最简单(即容易遵循做到)、最重要的几个规范开始,即追求 【有效性/复杂性】 最大化。

     联想到日程安排的十字表格,如法炮制了如下表格,以便分门别类:

代码审查
A(简单&很重要)C(复杂&很重要)
B(简单&较重要)D(复杂&较重要)

    当然,规范本没有重要与不重要之分,这里这样给其画上这样的标签,只是一个相对的概念,是给我们推进“代码审查”这项工作一个简单的指引,例如先实施A区的规则,一段时间后,当团队成员都习惯了这些规则,再实施B区的规则,基本上按照先易后难的顺序,依次推进。

    由于笔者的学识水平,以及经验所致,对一些规则的认识肯定存在偏差与不妥,还请同学批评赐教。

  《C++编程规范——101条规则、准则与最佳实践》(C++ Coding Standards——101 Rules, Guidelines and Best Practices)

组织和策略问题

 第0条(D): 不要拘泥于小节(又名:了解哪些东西不应该标准化)

      是的,有些东西不应该规定过死。但是我们认为,在一些个人风格和喜好方面,保持团队内部的一致性是有好处的。一致性的重要性似乎怎么强调都不过分。

第1条(B):在高警告级别下干净利落地进行编译

      将编译器的警告级别调到最高,高度重视警告。编译器是我们的好朋友,如果它对某个构建发出警告,就说明这个构建可能存在潜在的问题。这个问题可能是良性的,也可能是恶性的。我们应该通过修改代码而不是降低警告级别来消除警告。

第2条(C):使用自动构建系统

      “一键构建”,甚至使构建服务器根据代码的提交自动进行构建,持续集成,不断交付软件产品,在迭代中完善。尽管现在有了很多开源的自动化构建系统,但是搭建并维护这样一个自动化构建系统,需要团队中有一位经验丰富的高手。

第3条(B):使用版本控制系统(VCS)

       VSS, SVN, GIT。

第4条(*):做代码审查

      审查代码:更多的关注有助于提高质量。亮出自己的代码,阅读别人的代码。互相学习,彼此都会受益。代码审查无需太形式主义,但一定要做,团队可根据自己的实际情况尝试着去做,在做的过程中,慢慢改进,找到一个符合团队实际需要的方式。CppCheck

设计风格

第5条(C):一个实体应该只有一个紧凑的职责

      一次只解决一个问题:只给一个实体(变量、类、函数、名字空间、模块和库)赋予一个定义良好的职责。随着实体变大,其职责范围自然也会扩大,但是职责不应该发散。

第6条(C):正确、简单和清晰第一

      软件简单为美(KISS原则:Keep It Simple Software):质量优于速度;简单优于复杂;清晰优于机巧;安全第一。可读性:代码必须是为人编写的,其次才是计算机。

第7条(C):编程中应该知道何时和如何考虑可伸缩性

    面对数据的爆炸性增长,应该集中精力改善算法的O(N)复杂度。在这种情况下,小型的优化(例如节约一个赋值、加法或乘法运算)通常无济于事。

第8条(A):不要进行不成熟的优化

第9条(A):不要进行不成熟的劣化

     构造既清晰又有效的程序有两种方式:使用抽象(DIP)和库(STL)。

第10条(B):尽量减少全局和共享数据

第11条(C):隐藏信息

第12条(D):懂得何时和如何进行并发性编程

      线程安全?并发编程?加锁解锁死锁?这些对我来说还只是属于概念......,鄙视一下自己!

第13条(B):确保资源为对象所拥有。使用显式的RAII和智能指针

     利器在手,不要再徒手为之。当然,也要防止智能指针的过度使用。如果只对有限的代码可见(例如函数内部,类内部),原始指针就够用了。

编程风格

第14条(C):宁要编译时和连接时错误,也不要运行时错误

第15条(A):积极的使用const

     const是我们的朋友,不变的值更易于理解,跟踪和分析。定义值的时候,应该将const作为默认选项。用mutable成员变量实现逻辑上的不变性,在给某些数据做缓存处理的时候经常使用这一特性。即在类的const成员函数中可以合法的修改类的mutable成员变量。

     当然,对于那种通过值传递的函数参数声明为const 纯属多此一举,反而还会引起误解。

第16条(D):避免使用宏

     这似乎是C++中一条人人皆知的编程规范。可真正严格遵守的团队并不多(纯属猜想,哈哈)。

第17条(D):避免使用“魔数”

    同第16条。

    应该用符号常量替换直接写死的字符串(或宏)。将字符串与代码分开(比如将字符串放入一个独立的CPP文件中),这样有利于审查和更新,而且有助于国家化。

第18条(A):尽可能局部地声明变量

    避免作用域膨胀。变量的生存期越短越好。因此,尽可能只在首次使用变量之前声明之(通常这时你也有足够的数据对它初始化了)。

第19条(B):总是初始化变量。

    这里有两段很好的示例代码:

// 虽然正确但不可取的方式:定义变量时没有初始化
int speedupFactor;
if (condition)
    speedupFactor = 2;
else
    speedupFactor = -1;


以下两种方式更好一些:

// 可取的方式一:定义变量时即初始化
int speedupFactor = -1;
if (condition)
    speedupFactor = 2;  

// 较好且简练的方式二:定义变量时即初始化
int speedupFactor = condition ? 2 : -1;

 

第20条(D):避免函数过长,避免嵌套过深

第21条(C):避免跨编译单元的初始化依赖

第22条(A):尽量减少定义性依赖。避免循环依赖。

    尽可能的使用前置声明(forward declaration). Pimpl惯用法对遵循这一规范有实际性的帮助。DIP(依赖倒置原则)。

第23条(A):头文件应该自给自足

   各司其责:应该确保每个头文件都能够单独编译。

第24条(A):总是编写内部的#include保护符,决不要编写外部的#include保护符

函数与操作符

第25条(B):正确地选择通过值、(智能)指针或者引用传递参数

第26条(C):保持重载操作符的自然语义

第27条(C):优先使用算术操作符和赋值操作符的标准形式

     1)如果要定义 a+b,也应该定义 a+=b。一般利用后者实现前者,即赋值形式的操作符完成实际的工作,非赋值形式的操作符调用赋值形式的操作符。2)如果可能,优先选择将这些操作符函数定义为非成员函数,并将其和要类型T放入同一个名字空间中。3)非成员函数返回值或引用,成员函数返回引用。

帖几段示例代码:

// 成员函数 @= 
T& operator@=(const T& rhs)
{
     //.....具体的实现代码.....
     return *this;
}

// 非成员函数 @ 
T  operator@(const T& lhs, const T& rhs)
{
T temp = lhs;
return temp @= rhs;
}

// 非成员函数 @= 返回输入参数的引用
T& operator@=(T& lhs, const T& rhs)
{
    // ......具体的实现代码......
    return lhs; // 返回输入参数的引用
}

// 非成员函数 @ 
T operator@(T lhs, const T& rhs)
{
    return lhs @= rhs;
}

 

第28条(A):优先使用++和--的标准形式。优先使用前缀形式
      如果定义了++C,也应该定义 C++,而且应该用前缀形式实现后缀形式。

标准形式,示例代码:

//  前缀形式
T& operator++()
{
    // ......执行递增的实现代码
   return *this; // 返回递增后的新值
} 

// 后缀形式
T operator++(int) // 返回值
{
     T oldT(*this); // 先保存原值
      ++(*this);  // 调用前缀形式执行递增
      return oldT; //  返回原值
}

 

第29条(D):考虑重载以避免隐含类型转换

第30条(A):避免重载操作符&&, || 和,(逗号)

第31条(A):不要编写依赖于函数参数求值顺序的代码

     调用函数时,参数的求值顺序是悬而未定的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值