找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5375

积分

0

好友

710

主题
发表于 昨天 19:06 | 查看: 4| 回复: 0

之前在看源码的时候,看到下面这个实现:

for (__pp = __cp, void(), __cp = __cp->__next_; 
     __cp != nullptr; 
     __cp = __pp->__next_)

是的,for循环中有一个 void(),其在for循环语句中似乎完全没有意义,它什么也不做,没有任何副作用,就那么摆在那里。但,为什么标准里面会写出这种代码呢?

好了,直接给出答案吧:这是针对逗号运算符重载的防御性编程

众所周知,C++ 支持逗号运算符重载,就像下面这样:

template<typename T, typename U> 
T& operator,(T& left, U& right) {
    // 其他操作
    return left; 
}

这种则意味着 a, b 这样的表达式可能不会像“先计算 a,再计算 b”那样运行,相反,它可能会调用一个用户自定义的、行为任意的函数。

好了,接着我们看原始的循环程序:

__pp = __cp,__cp = __cp->__next_

这依赖于 内置的逗号运算符,它保证:

  • 从左向右求值
  • 顺序执行(左侧完全完成后,右侧才开始)

但如果任一操作数涉及具有重载的用户定义类型 operator,,则:编译器可能会调用该重载函数,而不是使用内置的逗号运算符。这将打破关于求值顺序的假设,这种行为往往是很危险的,尤其是在基础库中。

为了避免上面的问题,就引入了 void()

__pp = __cp, void(), __cp = __cp->__next_

这是因为

The comma operator cannot be overloaded if one of its operands is of type void()

翻译成中文就是:当逗号运算符的任意一个操作数是 void 类型时,逗号运算符不能被重载。

因此,前面的表达式就变成:

(__pp = __cp), void(), (__cp = __cp->__next_)

这样的话,就强制编译器使用内置的逗号表达式,而非用户重载的逗号表达式。

通过插入 void()

  • 求值顺序严格从左到右
  • 任何用户自定义的 operator, 都不能被执行。
  • 行为是确定性的且安全的

这正是标准库所需要的。

当然了,上面只是一个小技巧,还有其他的,比如笔者经常用的 (void)expr; 用来抑制未使用的警告,std::addressof() 避免重载 operator& 等等等等。

这一个小细节,它反映了 C++ 的一个更深层次的真理:编写健壮的通用代码不仅仅是关于应该发生什么——而是关于防范可能发生什么。




上一篇:Linux 内存排查:告别 free 迷信,从 available 与 swap 入手
下一篇:C++编译器为何生成多个析构函数?Itanium ABI与虚析构全解析
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-25 00:21 , Processed in 0.627020 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表