【让你的C++程序更加高效】条款01:尽量使用常量/内联而不是预处理器/宏定义

C++程序员分为两种,一种读过《让你的C++程序更加高效》,另一种则没有

Item 1:  Prefer const  and inline to #define.
OR "prefer the compiler to the preprocessor".
尽量使用const(常量)/inline(内联)而不是#define
OR "尽量依赖于compiler(编译器)而不是preprocessor(预处理器)"

例如某程序中包含有如下语句
#define ASPECT_RATIO 1.653

程序写好之后进行编译,首先preprocessor会将ASPECT_RATIO字样全部替换为1.653
于是预处理后的代码中有一大堆1.653,你甚至都不知道这些数字究竟是从宏ASPECT_RATIO
替换而来还是写代码时就输入的字面常量
之后的编译过程再也看不到ASPECT_RATIO这个符号了(参见symbolic table相关内容)

现在假设程序中用到这个ASPECT_RATIO的某个地方很关键并且可能导致出错
于是当出现错误或者进行调试的时候,也看不到ASPECT_RATIO这个符号,而只是看到
1.653这个“魔术般的数字”(magic number)
也许你心里清楚1.653这个数字是你自己定义的(你记得它),但这也不可取
更糟糕的是,如果这是第三方代码里面的,比如你的程序中引用了某个头文件
而这个头文件中包含了这条语句,那么在出错或者调试的时候,你甚至都不知道
1.653是个什么玩意儿,“从哪里冒出来的”,也许你需要花费大量精力去追踪它的来源

如果你养成了一个好的习惯,写了如下的代码
const double AspectRation = 1.653;

那么再出现上述问题的话,你可以很清楚地查看到出错信息是和这个double类型的常量
AspectRation有关(显然,也知道它的取值是1.653),因为这个常量的名字已经嵌入到了
symbolic table(符号表)中,在使用的时候只要说AspectRation就知道它是一个常量并且
知道它的取值为1.653(这是因为在symbolic table中保存了这个符号),这样在任何时候
都不用担心上面的那种让人迷惑的问题了
补充说明:程序进行编译之后,可能会有多个地方使用到了AspectRatio,这些地方都会用某个符号
(可能就是AspectRatio,也可能是其他符号,这要根据编译器的处理过程来判断)
当“使用者”(如某个函数请求输入参数)需要知道这个符号的值,“查”一下“表格”就知道了

下面我来举一个形象的例子(我自己杜撰的)
假设现在需要用一些散开的木板组装一套家具,几个关键的连接处需要精确对准(否则会不稳固)
和这些木板配套的有一些尺寸不一的测试板,它们是用来测试某个连接处相邻木板是否按照这个尺寸
对准(比如两块木板间距100cm,上下横跨20cm,用一块100cm*20cm的测试板顶在二者之间就可以了)
如果我是一个指导者,需要指导一个新手来装配这个家具,那么我会这样:
首先将几支测试杆标上记号,例如A,B,C,D,...,并且在组装图上带上对应标记,然后
在组装需要拼接两块木板的时候,我会告诉组装人员选取A测试板去测量一下
在拼接另两块木板时使用B测试板去测量一下,等等
但是,如果遇到这样的指导人员
“那个,用115cm*25cm的测试板;这边用110cm*30cm的测试板.。.”
组装人员会疯掉的(虽然你可能在测试板上标注了它的尺寸但还是太麻烦)

关于内联函数
假设你定义了这样的“宏函数”
#define MAX_VALUE(a,b)   a>b?a:b

一开始你会觉得这是”好机智的做法“,通常你也会把MAX_VALUE当做函数来使用,目的是寻找二者之中较大者
但是,请看以下语句
int x=1, y=3, z;
z=MAX_VALUE(x+1,y);

你觉得这段程序怎么样?
事实上,这段程序是有问题的,首先预处理器会进行替换,替换之后如下
int x=1, y=3, z;
z=x+1>y?x+1:y;

按照运算符的优先级,请读者自行推算

等等,你也许会辩解,你把上面的那个宏修改了一下,像这样
#define MAX_VALUE_P(a,b)   (a)>(b)?(a):(b)

事实上,这也不是万能的,举例如下
int x=1, y=3, z;
z=MAX_VALUE_P(++x,--y);

编译前预处理器会将这段代码替换成如下这样子
int x=1, y=3, z;
z=(++x)>(--y)?(++x):(--y);

我相信,这不是你想要的结果

现在,假如你这样定义一个内联函数
template<class T> inline const T& max(const T& a, const T& b) { return a > b ? a : b; }

其中的template<class T>表示这是一个模板,参数类型T
也可以写成template<typename T>
这是是一个模板函数,并且是内联的,寻找a和b之间的较大者

内联函数 大多数情况下会被编译器这样处理:
在每个使用到内联函数的地方,都将这个函数的代码嵌入到那个地方
而一般的函数,在调用到这个函数的时候先”中断“保存现场然后进行跳转,
执行完这个子函数后返回到中断处恢复现场继续执行后续步骤
这个”中断“及返回的过程会消耗额外的时间和代价
但内联函数不一样,因为在每一处调用都进行了代码展开,也就是说无需跳转,
现场执行,这样就加快了执行速度
不过,内联函数增加了编译器的代码展开以及程序的额外存储,但一般而言,那些常用的
并且短小精悍的代码(例如这里的max函数)都可以用内联函数
而那些庞大的代码或者很少使用的的函数则不建议这样做

模板函数 不能直接实例化,这里有一个模板参数T,例如遇到了int 类型的参数a和b那么
就可以实例化为下面的
inline const int& max(const int& a,const int&b) { return a>b?a:b; }

其他类型如float,double,char,short等等类似
这样,无论输入参数a和b是怎样的形式(只要能够确定其值并且都能转换为统一数据类型)都能正确处理

例如
int x=1, y=3, z, v;
z=max(x+1,y);
v=max(++x,--y);

都能得到你想要的结果

再注意 :在编写模板函数之前请检查C++ library中是否·已经提供了相关函数
例如这里的max函数,如果已经存在就不要再写了,除非你能够写一个更加高效的版本
或者你的程序限制了你不得不这样做

关于这个条款,还有一些高级内容,例如
const的使用
class(类)的static member(s) (静态成员)
etc.
稍后再抽空补充


注意:本条款以及后续许多条款在大多数情况下是effective的建议,但并不是绝对的。

本文原创,条款内容以及详解部分内容参考《Effective C++》
博文原始地址
http://blog.csdn.net/fengyhack/article/details/39576657
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值