《Effective C++》条款2:尽量以const、enum、inline替代#define

本文探讨了宏替换在编程中的潜在问题,包括错误追踪困难及安全性隐患,并提出使用常量和内联函数作为替代方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首选在宏替换是在预处理阶段进行,记住宏替换是最最最最简单的方式进行替换,也仅仅是做替换
原因一:
因为宏是进行最简单的宏替换,因此如果出现以下的情况

#define ASPECT_PATIO  213

在程序中所有的ASPECT_PATIO都被替换成213,可能会存在这样一个情况,使用了这个宏,但是出现了一个错误,但是编译器不会提到ASPECT_PATIO,反而会提到213,这样就可能存在一个情况,如果这个宏是我们自己定义的,我们可能会知道是什么错误,但是这个宏要是不是我们定义的,我们就很难知道错误在哪里。解决办法就是

const double Aspectpatio =213;

编译器在生成目标代码(obj)的时候,对于简单的宏替换可能会导致目标代码出现多份“213”,但是对于变量不会出现这个问题(本人没学过编译原理等底层课程,所以不知道编译器生成目标代码的过程)。
       同时通过常量替换#define的时候需要注意两种情况:
       ①
定义常量指针的时候使用string的常量对象更合适:

const char * const authorname="meyers";  //指针指向一个常量,不能通过指针修改常量值,指针指向也不能改

const std::string authorname ="meyers";

      ②如果是class的专属常量,需要将这个常量限制在class中,作为static成员

class GamePlayer
{
private:
    static const int Numturns;
}

const int GamePlayer::Numturns=5;

       但是这种情况可能也不适合某种情况,例如:数组声明必须知道数组的大小,编译器不允许“static 整数型 class常量”完成数组的大小设定, 可以通过枚举在解决这种情况。
     了解一下枚举:①枚举在某些方面比较像#define,取一个const变量的地址一般是合法的,但是取一个枚举类型或者一个#define类型就不合法,如果你不想别人的指针或者应用指向你的某个变量,枚举是一个选择②事实上 enum back是模板元编程的基础

class GamePlayer
{
private:
    enum{Numturns=5};
    int scores[Numturns];  //枚举值是常量不是变量
}


原因二:宏没有安全检查,可能存在安全隐患
 
       注意在定义宏的时候为所有的实参加上小括号,这样能保证减少错误,但是不能完全避免错误,看下 下面的代码,

#define CALL_WITH_MAX (a,b) f((a)>(b)?(a):(b))

int a=5,b=0;
CALL_WITH_MAX(++a,b);       //a被累计2次
CALL_WITH_MAX(++a,b+10);    //a被累计1次

a的递增次数在于和谁比较,因为宏仅仅做了替换,最简单的替换。这是不安全。我们可以通过内联函数的形式来替换这样的宏
 

template<typename T>
inline void CallWithMax(const T &a,const T &b )   //不知道T是什么类型,采用pass-byreference-to-const
{
    f(a>b?a:b);
}

这里的CallWithMax是个真正意义的函数,遵循作用域和访问规则,这样就是安全的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值