Item 02: Prefer consts, enums, and inlines to #defines

尽量以 const,enum,inline 替换 #define


假如有这样的语句:

#define ASPECT_RATIO 1.653

宏定义中的 ASPECT_RATIO 可能从未被编译器看见;也可能编译器处理之前就被预处理器给移走了。那么它很可能不会进入符号表,这样会给编译调试带来很大的困扰,浪费时间。

通常的解决之道是用常量替换宏:

const double AspectRatio = 1.653; 

这样,AspectRatio 肯定会被编译器看到,当然会进入符号表内。

当以常量替换 #defines,有两种情况值得关注:

  • 定义常量指针(constant pointers)时
    由于常量定义通常放在头文件内,因此有必要将指针(而不是指针所指之物)声明为const(常量指针,保证 指针本身不会被修改),如果想要在头文件内定一个 指向常量的指针常量,那么就必须写 const 两次:

    const char* const authorName = "Scott Meyers";
  • 类成员变量
    为了让常量在类中只有一份,必须定义成一个 static 成员:

class GamePlayer {
private:static const int NumTurns = 5; // 声明常量int scores[NumTurns];          // 使用该常量...
};

上面的 NumTurns 是一个声明而非定义。通常 C++ 要求你对你使用的任何东西提供一个定义式,但是如果它是成员变量且是 static 的且是整数类型(integral type,例如 ints,chars,bools),则需要特殊处理:

  • 只要不取它们的地址,那么就无需提供定义式
  • 但是如果需要取某个成员变量的地址,或者不取地址但是编译器却坚持要看到一个定义式,那就必须另外提供如下定义式:

    const int GamePlayer::Numturns; // NumTurns 的定义,不可以再设初值

    这个语句要放进一个源文件而非头文件。由于 它在声明时已获初值,因此不可以再设初值。

旧的编译器可能不支持上述语法,它们不允许 static 成员在声明的同时获得初值,此外所谓的”类内部设定初值”也只允许对整数常量进行。如果编译器不支持上述语法,那么可以将初值放在定义时设置:

class ConstEstimate {
private:static const double FudgeFactor; // static 常量声明...                              //位于 头文件 内
};const double                           // static 常量定义ConstEstimate::FudgeFactor = 1.35; // 位于 源文件内,不用加 static

有一种例外,就是类编译期间需要用到一个 类成员常量。比如上述的 GamePlayer::scores 数组声明式(编译器要求必须知道数组的大小),而这个时候假如编译器又不允许常量”在类内部设定初值”,这可咋办?可以使用 enum 代替,于是 GamePlayer 可定义如下:

class GamePlayer {
private:enum { NumTurns = 5 }; // "The enum hack" -- 令 NumTurns // 成为 5 的记号名称int scores[NumTurns];  // 这样就没问题了....
};

另一个常见的 #define 错误大家都应该很清楚,经常能遇到,就是 让宏看起来像函数,但是不会导致函数调用带来的开销

# 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 的增加次数居然取决于 “它被拿来和谁比较”!
这个时候 inline 来了!

template <typename T>
inline coid callWithMax(const T&a, const T& b) {f((a) > (b) ? (a) : (b));
}

有了 consts、enums 和 inlines,我们队预处理器的需求降低了,但并非完全消除(例如 #include、#ifdef/#ifndef)。目前不会完全引退,但是能避免使用就避免使用。

请记住

  • 对于单纯常量,最好用 const 对象或 enums 替换 #defines
  • 对于形似函数的宏,最好用 inline 函数替换 #defines

Item 02: Prefer consts, enums, and inlines to #defines相关推荐

  1. Effective C++记录(2):Prefer consts, enums, and inlines to #defines

    尽量用const, enum, inline 替换 #define 原因如下: 降低对预处理器的需求(#define). 弘定义对代码理解上存在巨大的开销(例如:带参弘定义,可能造成使用上的误解,以及 ...

  2. Effective C#: Item 3: Prefer the is or as Operators to Casts

    Item 3: Prefer the is or as Operators to Casts C#是强类型语言.我们要尽量避免类型转换. 有时我们必须要在runtime检查一个变量的类型.比如有时你要 ...

  3. Item 13: Prefer const_iterators to iterators.

    Item 13: Prefer const_iterators to iterators. Effective Modern C++ Item 13 的学习和解读. STL 中 const_itera ...

  4. Item 20: Prefer pass-by-reference-to-const to pass-by-value(Effective C++)

    Prefer pass-by-reference-to-const over pass-by-value. It's typically more efficient and it avoids th ...

  5. [EMC++] Item 8. Prefer nullptr to 0 and NULL

    条款八 倾向使用nullptr而非0和NULL 简介 在C++中的字面量0是一个int,当C++在一个只可以使用指针的情景中找到0,它勉强地把其解释为null指针. 对于NULL也有类似的问题,具体实 ...

  6. 《Effective Morden C++》Item 8: Prefer nullptr to 0 and NULL.

    引子 这一条目就比较简单了,就是宣传用nullptr来指代空指针,而不是之前的0或者NULL. 正文 在老式C++中,显然0是int类型,而NULL也是一个整数类型(int或者long).总的来说,这 ...

  7. Effective C++读书摘要--Accustoming Youself to C++

    <Item 1>View C++ as a federation of languages. 1.把C++看成4种子语言组成,即C.Object-Oriented C++.Template ...

  8. Effective C++读书笔记 摘自 pandawuwyj的专栏

    Effective C++读书笔记(0)       Start   声明式(Declaration):告诉编译器某个东西的名称和类型,但略去细节.   std::size_t numDigits(i ...

  9. Effective C++ 改善55个方法

    美·Scott Meyers 候捷 电子工业 2011 刚才看到个会议时间有点晚,3.25论文都提交了 谷歌去广告的插件, 最后投了这个会议,刚刚好正合适.我说金钱与时间 ACCUSTOMING YO ...

最新文章

  1. Mysql数据库 sql 语句调优
  2. ZYNQ 调试遇到的问题
  3. OpenCV使用形态学转换提取水平和垂直线的实例(附完整代码)
  4. 动态规划:从新手到专家
  5. 安装OpenCL和AMD驱动程序
  6. apt报错Hash 校验和不符解决办法
  7. JSEclipse安装后无法打开js文件_如何在你的 PC 上 下载并配置 Node.js
  8. To B 创业的本质,是求增速与生存环境的平衡
  9. ESP8266WIFI模块了解一下(新手入门级别)
  10. python 管道游戏_用Python做flybird游戏
  11. 支付宝 手机h5支付
  12. 微软live服务器地址,在Mail中设置windows Live hotmail方法
  13. 为什么阿里云ACE考试变难了?以后还能考吗?
  14. 微信小程序: 预览pdf,ppt,word等文件
  15. Python操控微信,实现微信机器人
  16. google earth engine随缘学习(十一)影像分割
  17. Java开发组装电脑_设计模式-组装电脑入门简单工厂
  18. 利用人工智能的模式辨识能力 由AI掌控的超音速飞机
  19. 移动端开发 面试技巧和注意事项
  20. 2013年中秋节桂林旅游

热门文章

  1. 金蝶系统服务器登录,金蝶云服务器如何登陆
  2. electron 桌面端业务中的小结(坑)
  3. appscan报告保存html,Appscan快速使用
  4. C语言笔记 第三章 键盘输入与输出
  5. zookeeper 进入客户端_ZooKeeper:第三方客户端 ZKClient
  6. SQL中的左连接与右连接,内连接有什么区别
  7. 如何理解vue中 同步异步
  8. 【Matlab路径规划】A_star算法机器人栅格地图路径规划【含源码 116期】
  9. Mysql-day01练习-计算每个班的男女人数
  10. 我来告诉大家win7和xp哪个好用