问题的历史:
宏来自C语言,是在预处理阶段自动化重复代码块的强大手段。在C++中,使用它们带来了灵活性,但也由于缺乏类型检查和预处理器的工作方式不明显,带来了许多隐藏的危险。
问题:
使用宏的主要风险:
解决方案:
在现代C++标准中,建议使用内联函数、模板、constexpr、枚举类以及constexpr变量来代替宏。
代码示例:
// 差: #define MAX(a, b) ((a) > (b) ? (a) : (b)) // 好: template<typename T> constexpr T max(T a, T b) { return a > b ? a : b; }
关键特点:
宏是否比内联函数更危险?
是的。宏不遵循语法和类型规则。传递具有副作用的参数时可能会出现意外结果。
#define SQUARE(x) ((x) * (x)) int y = 5; int z = SQUARE(y++); // y被递增了两次!
#include也是宏吗?
不是,#include是预处理器指令,但使用宏和include是相关的:可以通过宏修改要包含的文件列表(极不推荐)。
能像普通函数一样调试宏吗?
不能,调试器会展开宏并显示已经插入的文本,没有单独的命名实体。
在旧代码中定义了许多具有副作用的计算宏(例如,递增),这导致在新功能运行时出现难以捕捉的错误。
优点:
缺点:
在重构时,宏被替换为模板和constexpr函数,枚举类用于替代宏标志。
优点:
缺点: