任何其他带有链式插入运算符的陷阱

Any other gotchas with chained insertion operators?

本文关键字:插入 运算符 陷阱 其他 任何      更新时间:2023-10-16

所以,我今天早些时候在搞砸C++,特别是链接插入运算符。我注意到一些对我来说似乎很奇怪的事情。

#include <iostream>
using namespace std;
size_t& foo(size_t& n) {
    ++n;
    return n;
}
int main() {
    size_t bar = 5;
    cout << bar << " a " << foo(bar) << " b " << bar;
    cin >> bar;    //Ignore this, it's only here as an easy way to keep the window open
}

运行这个,而不是给5 a 6 b 6实际上给了6 a 6 b 5.显然,插入操作数是从右到左计算的,但随后从左到右打印,这可以解释为什么更新的值出现在函数调用之前,而原始值出现在函数调用之后。

当然,这可以通过简单地将cout foo(bar)放在自己的行上来解决,但我跑题了。

链接插入运算符时,我是否应该注意其他类似奇怪的事情?另外,有谁知道插入运算符为什么要这样做?

您正在读取 bar 两次,并为函数调用引用它一次,这会递增它。该函数调用相对于读取是不确定的排序的,这些读取彼此不排序,因此允许任何排序,并且未指定您获得的顺序。

你没有完全没有未定义的行为(一切都会),但未指定的行为并没有更有趣。以下是四个有效输出:

5 a 6 b 5
5 a 6 b 6
6 a 6 b 5
6 a 6 b 6

"链接插入运算符"只是函数调用。C++该语句中有一些关于函数调用的简单规则:

  1. 单个语句中的函数调用不交错 - 一个在下一个语句开始之前完成。(即语句内没有多线程)
  2. 当一个函数调用的
  3. 返回值是另一个函数调用的参数时,第一个函数调用必须在第二个函数调用之前发生。

没有规则规定单个函数的多个参数必须在调用之前连续或立即计算 - 排序规则集非常短。

现在我们在链中看到的是,不同的operator<<调用确实是链式的:第二个调用使用第一个调用的返回值。这就是为什么这些运算符都返回std::ostream& .因此,您的输出以正确的顺序显示。

在打印其返回值之前,必须调用具有相同逻辑的foo(bar)。但它可以在任何先前的时间调用。回想一下,没有规定必须同时计算单个函数的 2 个参数。第三个operator<<调用的两个参数是 foo(bar) 的返回值和第二个operator<<的返回值。因此,打印第三个值时,两者都必须发生。因此,a之后打印的数字是 6。

如果您声明结果应5 a 6 b 6,则假定第五个调用的第二个参数在第三个调用的第二个参数之后计算。根本没有这方面的规则。