C++一些建议

少用全局变量。

全局变量会增加代码流程理解的难度,DEBUG的难度。

一般某个变量在某处出错的时候,调试者都会想追溯变量从目前到出生的时刻,单线、顺序地查到看到底错误。 但是如果是使用全局变量,会发现这个变量的经历就像一团乱麻,你根本不知道它到底**在哪里被修改**的,你得漫山遍野地去搜索每一处它被修改的地方,如果说通过IDE可以全局查找还能勉强解决这个问题的话,另外一个很致命的点就是是,你不知道每一处的**先后顺序**,甚至有些地方虽然出现了该全局变量,但是实际上根本没有执行。这个问题工具也没有办法搞定,调试者只能硬着头皮调查每一处在实际运行的顺序。如果一个程序本身规模不大还好,但是一个模块上了万行,就会发现调试这东西是相当痛苦的,尤其是在调试别人代码的时候!

举个例子,调试者在DEBUG,如下面代码所述,my_main函数最后一行,例x被赋值给了y,在这一行看到了x异常,然后往前追溯,乍一看发现卧槽这个变量居然没有初始化,再一看,发现哦,这货是全局变量,但是这个变量在main函数里没有显式的出现(在子函数里出现称为隐式),然后只能搜索这货到底在哪里出现过,一搜,53处,卧槽!这个变量在函数a,b,c都出现过,而且在my_main函数之前也出现过,调试者得review每一个地方的代码,理一遍逻辑才能知道有没有出错。

int a;
a(){if(0) x =3; }
b(){x=10;}
c(){if(z>Z) x=4; }
void my_main()
{
 a(); // 一些函数
 b();
c();
 int y = x;
}

有的人说我看着代码也不是很复杂啊,随便一看下就知道了。是的,代码简单是没问题,但是如果

  • 前面的abc三个函数增加到**几千行**,
  • 而且**互相调用**,**调用的深度**有5、6层,
  • 函数处于**不同的源文件**,
  • 每一处变量的修改充斥着非常多的**数学运算**,
  • 伴随着许多**类似的变量名**,x0,x1,xx,my_x,这些变量和x相互作用,相互转化。。。
  • 这个变量不是简单的什么float,int类型或者结构体,而是一张图像内存,这个图像内存buffer你得加一些代码show出来或者save才能看到。
  • 和它一样生猛的全局变量在这个模块还有十几甚至几十个。。。

这时候就会理解此时的痛苦了。

传参的时候变量名不要频繁换马甲

变量名每次进入一个子函数就会换一个名字,有时候调试的时候真的不好把握,总得调到definition和callee那里查看两个变量是不是一样的。 特别是当版本变更时,例如本来函数f处于第二层,由于版本变更,第二层函数被干掉了,只好带着f直接来到一层,然后发现曾经的二层函数给f的实参在一层里名字完全变了,这时候又要回退版本,找曾经的二层函数给f的参数在一层函数到底是哪些。

名字的变更例如,从index到image_index再到frame_index,从direction到image_direction再到direction。。。 变量名在进入多级函数时,最好**保持不变**,这样在修改代码的时候不用**频繁去check**形参和实参是否正确。 变量可见区域的划分目的就是让程序员能在不同的函数用同一个变量名。

如何用驼峰命名法命名大写缩写?

大写缩写会使得我们使用驼峰命名法是感到困扰,如果全部大写,就会失去区分单词的能力,如果后面小写,这失去了缩写的表达能力。 微软的规范就是:如果缩写词是2个字母,那么全部大写,如果缩写词大于等于3个,那么当做普通单词,即头字母大写,后面小写。 例如IOExport,ImuHeader,这样的话如果看到了3个大写字母,说明第三个字母是下一个单词了首字母。

header only模式开发效率低!

header only 编程模式虽然让使用者很爽,不需要在编译配置中添加源文件,但是缺点也很明显,其中一个就是编译时间很长,哪怕是个人编程,也会尽量复用各种代码,如果这些基础代码是header only形式,那么开发者在改动-编译-调试过程中,编译会占用很多的时间,改动一两处,有可能需要3-5分钟的编译。 权衡两者,还是选择提高编译速度,放弃header only开发。