本篇文章,博主将会为大家梳理出大家在日常编程时遇到的问题
第一章 基础问题
说一个问题是基础的,并不就是说他不是严重的或者不是普通存在的。事实上,本章所讨论的基础问题的共同特点比起在以后章节讨论的技术复杂度而言,可能更侧重于使人警醒。这里讨论的问题,由于他们的基础性,在某种程度上可以说他们普通存在于几乎所有的C++代码中。
———————————————————————————————————————————
常见错误1:过分积极的注释
很多注释都是画蛇添足,他们只会让源代码更难读,更难维护,并经常把维护工程师引入歧途。考虑下面的简单语句。
a=b;//将b赋值给a
这个注释难道比代码本身更能说明这个语句的意义吗?因为它说话是完全无用的。事实上它比完全无用还要坏。它是害人精。首先,这条注释转移了代码阅读者的注意力。增加了阅读量,而因使代码更费解。其次,要维护的东西更多了,因为注释也要随着它描述的代码的更改而更改的。最后这个注释的更改常常被遗忘。如果只修改程序忘更改注释就会变成以下语句。
c=b;//将b赋值给a;
仔细的维护工程师不会顿悟的说注释是错的,说不定代码错了呢。所以他就被迫要去节省整个程序,以确定到底是注释错了呢还是有意而为的呢?(c可能是a的引用),还是本来正确,只是比较间接的呢(赋值给c可能引发一些传播效应以使a的值也发生相应的变化),等等,总之这一行就根本不应该带注释。
a=b;
还是这代码本来的样子最清楚的表明了其意义,也没有额外的注释需要维护。这在精神上也符合老生常谈,以及“最有效的代码,就是根本不存在的代码”。这条经验对于注释也适用了:最好的注释就是根本用不着写的注释,因为要注释的代码已经“自注释”了。
———————————————————————————————————————————
常见错误2:幻数
幻术用在这里,其含义是上下文里出现的果字面常量(raw numeric literal),本来他们应该是具名常量(named constant)才对:
class Portfolio{
//...
Contract *contract_[10];
char id_[10];
};
幻术带来的主要问题是他们没有语义,他们只是个量罢了。一个"10"就是一个"10",你看不出他的意思是"合同的数量"或是"标识符的长度"。这就是为什么当我们阅读和维护带有幻术的代码时,不得不一个个的去搞清楚每个光秃秃的量到底代表什么意思。没错,这样也能勉强度日,但带来的是不必要的精力浪费以及准确性的牺牲。
就拿上面这个设计的很差的表示公文包(portfolio)的性别来说,他就能够管理最多10个合同。当合同数越来越多的时候(10个不够用了),我们决定把合同数增加至32个(如果你对安全性和正确性很挑剔,那最好是改用STL中的vector组件)。我们立刻陷入了困境,因为必须一个个去检查那些用了portfolio型别的源文件里出现的每一个字面长量“10”,并逐个每个“10”是不是代表“最多合同数”这个意思。
———————————————————————————————————————————
常见错误3:全局变量
很难找到任何理由去硬生生的声明什么全局变量。全局变量阻碍了代码重用,而且使代码变得更难维护。他们阻碍重用是因为任何使用了全局变量的代码就立刻与之藕合,这使得全局变量一改它们也非得跟着改,从而使任何重用都不可能了。他们使代码变得更难维护的原因是很难甄别出哪些代码用了某个特定的全局变量,因为任何代码都有访问他们的权限。
全局变量增加了模块间的耦合。因为他们往往作为幼稚的模块间消息传递机制的设施存在。就算他们能担此重任,从实践角度来说,要从大型软件的源代码中去掉任何全局变量都几乎不可能。这还是说他们能正常工作的情况。不过可不要忘了,全局变量是不设防的。随便哪个维护你代码的是C++新手,都能让你对全局变量有热烈依赖的软件所玩的把戏随时塌台。
———————————————————————————————————————————
常见错误4:未能区分函数重载和形参默认值
函数重载和形参默认值之间其实并无干系。不过这两个独立的语言特征有时会被混淆,因为他们会模塑出语法上非常相向的函数用法接口。当然看似一些接口及背后的抽象意义却大相径庭。
gotcha04/c12.h
//...
C1 a;
a.fi(0);
a.f1();
gotcha04/c12.h
class Ca{
public:
void f1(int arg = 0);
//...
};
型别C1的设计者决定给与函数f1()一个形参的默认值。这样一来,C1的使用者就有了两个选择:要么显式地函数f1()一个实参,要么通过不指定任何参的方式隐式的给函数f1()一个实参0。所以,上述两个函数调用产生的动作序列是完全相同的。
———————————————————————————————————————————
常见错误5:对引用的认识误区
对于引用的使用,主要存在两个常见问题。首先,他们经常和指针搞混。其次,他们未被充分利用。好多在C++工程里使用的指针,实际上只是C阵营那些老顽固的节奏,该是引用翻身的时候了。
引用并非指针。引用只是其初始化物的别名。记好了,能对引用作的唯一操作就是初始化它。一旦初始化结束,引用就是其初始化物的另一种写法罢了。引用是没有地址的,甚至他们有可能不干任何存储。
int a = 12;
int &ra = a;
int *ip = &ra;
a = 42;
由于这个原因,声明引用的引用、只射到引用的指针或引用的数组都是不合法的。
int &&rri = ra;//错误!
int &*pri;//错误!
int &ar[3];//错误!
引用不可能带有常量性或挥发性,因为别名不能带有强亮性或挥发性。尽管引用可以是个带有常量性或挥发性的实体的引用。如果用关键词count或volatile来修饰引用,就会收到一个编译器的错误:
int &const cri = a;//错误!
const int &rci = a;//没问题!
是如果把count或volatile修饰加在引用型别上面并不会被C++语言判定为非法。编辑器不会为此报错,而是简单的忽略这些修饰词。
———————————————————————————————————————————
常见错误6:对常量的认识误区
在C++中的常量性概念是平凡的,但是这和我们对const先入为主的理解不太符合。首先我们要特别注意以修饰的变量声明和字面常量的区别。
int i = 12;
const int ci = 12;
字面常量12不是C++概念中的常量,它是个字面常量。字面常量没有地址,永远不可能改变其值。i是个对象。有自己的地址。其数值可以变化。用const关键词修饰声明的ci也是个对象。有自己的地址。尽管在本例中其实不可变。
我们说i和ci可以作为左值使用,而自内常量12却只能作为右值。这两个术语来源于伪表达式L=R,说明只有左值能出现在赋值表达式左侧,右值则只能出现在赋值表达式右侧。但这种定义对C++和标准C来说并不成立,因为在本例中ci是组织,但不能被赋值,因为它是个不可修改的左值。
如果把左值理解为能放置值的地方,那么右值就是没有与之相关地址的值。
int *ipl = &12;//错误!
12 = 13;//错误!
———————————————————————————————————————————
常见错误7:无视基础语言的精妙之处
大多数C++软件工程师都自信满满的认为自己对所谓C++的“基础语言”,也就是C++继承自C语言的那部分了如指掌。实际情况是即使经验丰富的C++软件工程师,有时候也会为基础的C/C++语句和运算符的某些妙用一无所知。
逻辑运算符不能算是难懂,对吗?但刚入行的C++软件工程师却总是不能让他们物尽其用。你看到下面的代码时是不是会怒从胆边生?
bool r = false;
if(a<b)
r=ture;
正解如下:
bool r = a<b;
还有很多软件工程师都把"如果条件运算符表达式的两个选择结果都是左值,那么这个表达式本身就是个左值"这回事儿忘在脑后了。 所以必然有些人就会写出如此代码。
//版本一
if( a < b )
a = val();
else if( b < c )
b = val();
else
c = val();
//版本二
a<b ? ( a = val() ) : b<c ? ( b = val() ) : ( c = val() );
而对C++怀有正确观念的熟手稍加点化。上述代码马上变得短小精悍,简直酷毙了。
//版本三
(a<b?a:b<c?b:c) = val();
———————————————————————————————————————————
常见错误8:未能区分可访问性和可见性
C++语言压根儿没有实现什么数据隐藏,它实现了的是访问层级。在class中具有protected和private访问层级并非不可见,只是不能访问罢了。如同一切可见而不可及的事物一样,他们总是惹出各种麻烦。
———————————————————————————————————————————
常见错误9:聪明反被聪明误
C++语言十分神奇,有时在你认为空格无用或可有可无时,它会给你致命一击:
a+++++b;//错误!
a+++ ++b;//没问题!
以下两行也如出一辙
ptr->*m;//没问题!
prt-> *m;//错误!
聪明反被聪明误是C++软件工程师一个常见的问题。所以,请时刻牢记:几乎所有场合下,遵循习惯用法、清晰的表达和一点点效率的折损都好过小聪明、模棱两可和维护便利的丧失。
———————————————————————————————————————————
常见错误10:嘴上无毛,办事不牢
记住以下几点,能让你在工作上不欠情商之苦:
首先,我们要对我们自己选择的专业负责。从而我们应该做出有质量的工作,并在我们的能力范围内做到最高标准。
其次,我们对身处的社会与居住的星球负责。我们选择的专业在科学研究和实际服务的方面的是平等一员。
第三,我们对参与的社区负责。所以我们应用共享我们的长处,来影响社区公共策略。
第四,我们对同事负责。所以我们应该有大度风范。
第五,我们要对同行负责。从而,我们应该共享知识与经验。
最后,我们要对自己负责。我们的工作的思想起码应该让我们自己感到满意,并让我们自己自己决定选择这一行情有可原。
这时,这些责任就不在是一种负担,而是快乐了!
第一章到此结束,我们下一章节再见!
如有疑问,欢迎大家在评论区留言!!!
237

被折叠的 条评论
为什么被折叠?



