Effective C++ 条款02:尽量以const,enum,inline替换 #define
换一种说法就是宁可以编译器替换预处理器
举例
#define ASPECT_RATIO 1.653
记号ASPECT_RATIO也许从未被编译器看见;也许在编译起开始处理源码前它就被预处理器移走了,于是它并没有进入符号表,当出现编译错误的时候会提示1.653,但是不会提示ASPECT_RATIO。
解决办法就是用一个常量替换宏(#define):
const double AspectRatio = 1.653;
常量替换宏的两种特殊情况
1. 常量指针
- 常量定义通常被放在头文件内(以便被不同的源码含入)
- 常量的(不变的)char*-based:
const char* const authorName = "Scott Meyers";
const std::string authorName("Scott Meyers"); (C++最好用这种方式)
2. class专属常量
- 为了将常量的作用域限制于class内,必须让它成为class的一个成员;而为确保此常量至多只有一份实体,必须让它成为一个static成员:
class GamePlayer {
private:
static const int NumTurns = 5; // 常量声明式
int scores[NumTurns]; // 使用该常量
}
- 如果编译器坚持要看到一个定义式,那么就必须提供以下定义,并且把它放入实现文件而非头文件,因为class常量已在声明时获得初值,因此定义时不可以再设初值。
const int GamePlayer::NumTurns; // NumTurns的定义;
无法利用#define 创建一个class专属常量,因为#define并不重视作用域(scope)。一旦宏被定义,它就在其后的编译过程中有效(除非在某处被#undef)。
旧式编译器也许不支持以上语法,它们不允许static成员在其声明式上获得初值。此外所谓"in-class 初值设定",也只允许对整数常量进行。应该改成如下形式:
class CostEstimate {
private:
static const double FudgeFactor; // static class 常量声明位于头文件
};
const double CostEstimate::FudgeFactor = 1.35; // 位于实现文件内
- 如果编译起不允许“static 整数型class常量”完成"in class 初值设定",可改用所谓的"the enum hack" 补偿做法。其理论基础是“一个属于枚举类型的数值可权充ints被使用”,见如下定义:
class GamePlayer {
private:
enum {NumTurns = 5};
int score[NumTurns];
}
用inline替换形似函数的宏(macros)
// 以a和b的较大值调用f
#define CALL_WITH_MAX(a, b) f((a) > (b)?(a):(b))
- 无论何时当你写出这种宏,你必须记住为宏中的所有实参加上小括号,否则某些人在表达式中调用这个宏时可能会遇到麻烦。但纵使你为所有的实参加上小括号,看看下面不可思议的事情:
int a = 5, b = 0;
CALL_WITH_MAX(++a, b); // a被累加两次
CALL_WITH_MAX(++a, b + 10); // a被累加一次
template<typename T>
inline void callWithMax(const T& a, const T& b) { // 由于我们不知道T是什么,所以采用pass by reference-to-const
f(a > b ? a:b);
}
总结
- 有了const,enum,inline,我们对预处理器(特别是#define)的需求降低了,但并非完全消除。#define仍然是必需品,而#ifdef/#ifndef也继续扮演控制编译的重要角色。
请记住
- 对于单纯常量,最好以const对象或enums替换#define
- 对于形式函数的宏(macros),最好改用inline函数替换#define
Effective C++ 条款02:尽量以const,enum,inline替换 #define的更多相关文章
- Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define
尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...
- Effective C++阅读笔记_条款2:尽量以const,enum,inline替换#define
1.#define缺点1 #define NUM 1.2 记号NUM可能没有进入记号表,在调试或者错误信息中,无法知道1.2的含义. 改善:通过const int NUM = 1.2; 2.#dein ...
- 条款02:尽量以const,enum,inline替换#define
目录 1. 总结 2. 使用const常量或enum替换宏常量 class外部的常量指针 class专属常量 1. 总结 对于单纯常量,最好以const常量或enum替换#define 对于宏代码段, ...
- 读书笔记_Effective_C++_条款二:尽量以const, enum, inline替换#define
其实这个条款分成两部分介绍会比较好,第一部分是用const和enum替换不带参的宏,第二部分是用inline替换带参的宏. 第一部分:用const和enum替换不带参宏 宏定义#define发生在预编 ...
- 条款2:尽量以const, enum, inline替换#define
原因: 1. 追踪困难,由于在编译期已经替换,在记号表中没有. 2. 由于编译期多处替换,可能导致目标代码体积稍大. 3. define没有作用域,如在类中定义一个常量不行. 做法: 可以用const ...
- NO.2: 尽量以const,enum,inline 替换 #define
1.首先#define 定义不重视作用域(scope),虽然可以#undef控制,但是不美观,还存在多次替换的问题,以及没有任何封装性. 2.const XXX_XX,保证其常量性以及可控的作用域,如 ...
- Effective C++ -----条款02:尽量以const, enum, inline替换 #define
class GamePlayer{private: static const int NumTurns = 5; int scores[NumTurns]; ...}; 万一你的编译器(错误地)不允许 ...
- Effective C++之条款2:尽量以const enum inline替换 #define
本文的标题也可以改成“用编译器替换预处理器”: const double AspectRatio = 1.653; //最好使用上述代码替换下述代码: #define ASPECT_RATIO 1.6 ...
- 条款2:尽量使用const ,enum,inline替换define
宁可使用编译器而不用预处理器 假设我们使用预处理器: #define ABC 1.56 这标识符ABC也许编译器没看到,也许它在编译器处理源码前就被预处理器移走了,于是“标识符”ABC没有进入标识符列 ...
- Book. Effective C++ item2-尽量使用const, enum, inline替换#define
##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...
随机推荐
- 分布式服务框架:Zookeeper简介
分布式服务框架:Zookeeper(分布式系统的可靠协调系统) 本文导读: 1 Zookeeper概述 2 Zookeeper总体结构 ——逻辑图.运转流程.特点.优点.数据结构 3 Zookeepe ...
- git和svn的详细对比
近期就[版本管理工具是否进行切换SVN->Git]的问题进行了讨论,于是对svn和Git进行了相关研究,进而梳理出Git的特点(优.缺点),最后将Git与SVN进行了对比,对比结果详见下方内容. ...
- 【APIO2014】Palindromes
#103. [APIO2014]Palindromes 统计 描述 提交 自定义测试 给你一个由小写拉丁字母组成的字符串 ss.我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这 ...
- 【BZOJ4317】Atm的树 动态树分治+二分+线段树
[BZOJ4317]Atm的树 Description Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径 ...
- js获取当前日期事件(yyyy-MM-dd HH:mm:ss)
function getDataTimeNow() { var nowstr = new Date(); var datenow = nowstr.getFullYear() + "-&qu ...
- Powershell Function Get-PendingReboot
获取系统中Restart Pending的计算机 $servers=get-content D:\serverlist.txt Get-PendingReboot -ComputerName $ser ...
- php 正则表达式四,例子
PHP常用正则表达式汇总:http://bbs.php100.com/read-htm-tid-83266.html 1.非空匹配: .+ 2.浮点数匹配: ^\d+.\d{2}$ 3.手机号匹配: ...
- Backtracking is a form of recursion.
w https://www.cis.upenn.edu/~matuszek/cit594-2012/Pages/backtracking.html Starting at Root, your opt ...
- 模块 - random/string/os/sys/shutil/zipfile/tarfile
random 模块 方法: >>> random.randint(1,3) #会包含 1 2 3 3 >>> random.randrange(1,3) #会包含 ...
- 注册tomcat为windows服务(转载)
第一部分 应用场景 需要服务器上Tomcat不显示启动窗口 需要服务器上Tomcat开机自启动 ... 第二部分 配置过程 一.修改配置文件 1 {Tomcat_HOME}/bin/service.b ...