当前位置: 首页 > ops >正文

Effective C++ 条款02:尽量以 const, enum, inline 替换 #define

Effective C++ 条款02:尽量以 const, enum, inline 替换 #define


核心思想:使用编译器可处理的实体代替预处理器宏,避免宏的副作用,增强类型安全性和调试能力。

主要问题及解决方案:
问题类型#define 的缺陷替代方案优势
常量定义无类型检查、不进入符号表、作用域不受控const 常量类型安全、可调试、作用域控制
类内常量无法在类内初始化静态整型常量enum 枚举常量不占用内存、编译器可见、类作用域
函数宏易引发多次求值、参数副作用、无类型检查inline 函数类型安全、避免多次求值、可调试

代码示例

1. 用 const 替换常量宏
// 不良实践:宏常量
#define PI 3.14159
#define MAX_BUFFER 1024// 改进方案:const常量
const double kPi = 3.14159;        // 类型明确
const int kMaxBuffer = 1024;        // 进入符号表
const char* const kAuthor = "Scott Meyers";  // 常量指针// 类作用域常量
class Circle {
private:static const int kDefaultRadius = 10;  // 类内初始化(整型)const double kScaleFactor;             // 成员常量
public:Circle() : kScaleFactor(1.5) {}       // 初始化列表初始化
};
2. 用 enum 实现类内常量
class GamePlayer {
private:// 当编译器不允许静态整型常量类内初始化时enum { kMaxPlayers = 6 };  // enum hackint scores[kMaxPlayers];   // 编译期确定数组大小public:void printMax() {// kMaxPlayers 不会分配内存,无法取地址std::cout << "Max players: " << kMaxPlayers; }
};// 模板元编程中的enum hack
template<int N>
struct Factorial {enum { value = N * Factorial<N-1>::value };
};
template<>
struct Factorial<0> {enum { value = 1 };
};
3. 用 inline 替换函数宏
// 危险宏:参数可能被多次求值
#define SQUARE(x) ((x) * (x)) // 改进方案1:模板内联函数
template<typename T>
inline T square(const T& x) { return x * x; 
}// 改进方案2:带作用域的宏替代
inline int safeSquare(int x) { return x * x; 
}// 测试案例
int main() {int a = 5;// 宏的陷阱:SQUARE(++a) -> ((++a)*(++a)) = 7*7=49 (a=7)std::cout << "Macro: " << SQUARE(++a) << ", a=" << a << "\n"; a = 5;// 安全调用:square(++a) -> 6*6=36 (a=6)std::cout << "Inline: " << square(++a) << ", a=" << a; return 0;
}

输出

Macro: 49, a=7   // 不符合预期的结果
Inline: 36, a=6  // 符合预期

关键总结

场景替代方案核心优势
全局/命名空间常量const 常量类型安全、调试可见、作用域控制
类内整型常量enum 枚举常量不分配内存、避免静态初始化顺序问题
类内非整型常量static const + 类外定义类型安全、符合标准
函数式宏inline 函数(或模板函数)避免多次求值、类型检查、支持作用域规则

编程启示

  1. 宏在预处理阶段被替换,编译器看不到宏符号,增加调试难度
  2. 优先使用编译器可见实体(const, enum, inline
  3. enum hack 在模板元编程和资源受限环境中仍有价值
  4. 现代 C++ 中 constexpr 可进一步替代部分场景(C++11 起)
http://www.xdnf.cn/news/16252.html

相关文章:

  • 【PyTorch】图像多分类项目部署
  • epoll_event数据结构及使用案例详解
  • 解密负载均衡:如何轻松提升业务性能
  • Qt:qRegisterMetaType函数使用介绍
  • iOS —— 天气预报仿写总结
  • 【日志】unity俄罗斯方块——边界限制检测
  • Zookeeper学习专栏(十):核心流程剖析之服务启动、请求处理与选举协议
  • Java测试题(上)
  • 《设计模式之禅》笔记摘录 - 10.装饰模式
  • gig-gitignore工具实战开发(四):使用ai辅助生成gitignore
  • AI图像编辑能力评测的8大测评集
  • ComfyUI中运行Wan 2.1工作流,电影级视频,兼容Mac, Windows
  • Elasticsearch-9.0.4安装教程
  • 05.原型模式:从影分身术到细胞分裂的编程艺术
  • RAG、Function Call、MCP技术笔记
  • 1 51单片机-C51语法
  • 免模型控制
  • Android Camera setRepeatingRequest
  • c语言-数据结构-沿顺相同树解决对称二叉树问题的两种思路
  • 算法:数组part02: 209. 长度最小的子数组 + 59.螺旋矩阵II + 代码随想录补充58.区间和 + 44. 开发商购买土地
  • KNN算法
  • 构建敏捷运营中枢:打通流程、部署与可视化的智能引擎
  • 【前端工程化】前端项目开发过程中如何做好通知管理?
  • 数仓主题域划分
  • FreeRTOS-中断管理
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘streamlit’问题
  • 与 TRON (波场) 区块链进行交互的命令行工具 (CLI): tstroncli
  • ISAAC ROS 在Jetson Orin NX上的部署
  • Mkdocs相关插件推荐(原创+合作)
  • 目标导向的强化学习:问题定义与 HER 算法详解—强化学习(19)