德洛瓦:被弃之族免安装正式版
3.63G · 2025-10-22
这个条款的核心思想是:优先使用编译器而非预处理器。#define
是预处理器指令,在编译前进行简单的文本替换,这会带来多种问题。我们应该用C++语言特性来替代它。
#define
?问题1:符号表缺失
#define PI 3.14159
PI
替换为3.14159
PI
这个符号,调试时错误信息只会显示3.14159
问题2:类型安全缺失
#define
不进行类型检查,只是文本替换问题3:作用域问题
#define
不受命名空间、类作用域限制问题4:边际效应(函数宏)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int x = 5, y = 3;
int z = MAX(++x, y); // 展开后:((++x) > (y) ? (++x) : (y))
// x可能被递增两次!
2.1 用const
替换常量宏
普通常量:
// 不好的做法
#define PI 3.14159
#define AUTHOR "Scott Meyers"
// 好的做法
const double Pi = 3.14159; // 类型安全,编译器可见
const char* const Author = "Scott Meyers"; // 常量指针,指向常量字符串
类专属常量:
class GamePlayer {
private:
// 好的做法:类内静态常量
static const int NumTurns = 5; // 常量声明
int scores[NumTurns]; // 使用常量
// ...
};
// 需要在实现文件中定义(如果取地址或某些编译器需要)
const int GamePlayer::NumTurns; // 定义
2.2 用enum
替换常量宏
当编译器不支持类内初始化时:
class GamePlayer {
private:
enum { NumTurns = 5 }; // "enum hack"技巧
int scores[NumTurns]; // 合法使用
// ...
};
enum hack
的优势:
#define
(不能取地址,不会分配内存)2.3 用inline
替换函数宏
函数宏的问题:
// 危险的宏函数
#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递增一次
安全的inline
函数:
// 模板内联函数 - 类型安全,无边际效应
template<typename T>
inline void callWithMax(const T& a, const T& b) {
f(a > b ? a : b);
}
// 使用安全
int a = 5, b = 0;
callWithMax(++a, b); // a只递增一次,行为可预测
const
对象static const
成员或enum
inline
函数或模板函数const char* const
例外情况:#define
在条件编译、平台特定代码、字符串化操作(#
)和令牌连接(##
)中仍有其价值,但这些属于特殊情况。
核心记忆点:让编译器看到你的代码,而不是让预处理器盲目替换。使用C++语言特性获得类型安全、作用域控制和更好的调试体验。
华为鸿蒙 HarmonyOS 6 支持与苹果 iOS / iPadOS / macOS 互传体验
Netflix 宣布全力投入 AI:“能帮人类把故事讲得更好”