为什么我应该在c++中避免使用宏?
Why should I avoid macros in C++?
我读过很多书& &;我应该避免在c++中使用宏。好吧,但为什么呢?我不明白。它们非常有用,经常在c中使用。
谁能(非常)详细地解释一下,为什么我应该在c++中避免使用它们?
宏不尊重作用域规则,而是在文本级别操作,而不是语法级别。由此产生了许多陷阱,这些陷阱可能导致奇怪的、难以隔离的bug。
考虑下面这个众所周知的例子:
#define max(a, b) ((a) < (b) ? (b) : (a))
⋮
int i = max(i++, j++);
在这种情况下,首选的替代方案是函数模板:
template <typename T>
T max(const T & a, const T & b) { return a < b ? b : a; }
下面是另一个导致微妙问题的例子:
#define CHECK_ERROR(ret, msg)
if (ret != STATUS_OK) {
fprintf(stderr, "Error %d: %sn", ret, msg);
exit(1);
}
⋮
if (ready)
CHECK_ERROR(try_send(packet), "Failed to send");
else
enqueue(packet);
您可能认为解决方案就像将CHECK_ERROR
的内容包装在{ … }
中一样简单,但是由于;
在else
之前,因此无法编译。
为了避免上述问题(else
附加到CHECK_ERROR
的if
而不是外部的if
),应该在do … while (false)
中包装这样的宏,如下所示(也避免重复的ret
):
#define CHECK_ERROR(op, msg)
do {
int ret = (op);
if (ret != STATUS_OK) {
fprintf(stderr, "Error %d: %sn", ret, msg);
exit(1);
}
while (false)
这对宏的含义没有影响,但确保整个块始终被视为单个语句,并且不会以令人惊讶的方式与if
语句交互。
长话短说,宏在很多层面上都是危险的,因此应该只在万不得已的时候使用。
相关文章:
- 我应该使用什么来代替void作为变体中的替代类型之一
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 我应该删除矢量<short>吗?
- 我应该如何修改此代码以使用给定字符串中的字母打印菱形图案
- 我应该在锁定TBitmap画布后解锁它吗
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 我应该避免多重实现继承吗
- 为了方便起见,我应该避免公开私有字段变量吗
- 我收到同义重复编译器错误。我应该如何修复"类型"X"的参数与类型"X"的参数不兼容?
- 违反const正确性:我应该现实地期待什么问题
- 我应该如何表示我拥有的连续元素序列?
- 我应该将除 .cpp 以外的其他文件添加到 git 中吗?
- 我应该如何从 stdin C++ 中读取可变长度的格式字符串?
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 我应该如何捕捉out_of_range异常?
- 我应该声明所有不抛出 noexexcept 的成员/函数吗?
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 如果条件不相关,我应该更喜欢两个 if 语句而不是 if-else 语句吗?