关于c++的ostream

About ostream of c++

map<string,int> m;
string str;
while (cin >> str){
    ++m[str];
}
map<string, int>::const_iterator iter = m.begin();

while (iter != m.end()){
    cout << iter->first << (iter++)->second << endl;
}
return 0;

上面是代码,但是编译器给我一个关于无效解引用的错误,所以我 像这样更改最后一行:

cout<<(iter++)->first<<iter->second<<endl;

我得到了正确的答案,我的问题是cout做了什么让我不得不这样写,它是从后到前读取字符串吗?它是如何实现的? 还是我其他地方错了?

<< 运算符可以按任何顺序计算其操作数。在你的情况下,它可能在 iter->first.

之前评估 (iter++)->second

你应该把你的 iter++ 放在下一行。

您面临的问题是可以通过多种方式对其进行评估。问题是 each operator<< 可以先评估其左侧,然后再评估其右侧,反之亦然。由于您拥有三个,因此可能有很多变体。

现在您尝试使用 iter 两次,并在一个语句中对其进行修改,而不对 sequence 进行任何操作。这使它成为未定义的行为。什么事都有可能发生。

修复:使用两个语句。语句按明显的顺序排列。

给定 a << b 形式的表达式,ab 都必须求值,但它们求值的顺序是未指定的,这意味着任何顺序都是允许的(a 首先,b 首先,两者同时以某种方式)。

当链接多个这样的表达式时也是如此,例如 a << b << c.

实际上,重载运算符是作为函数调用实现的。例如

std::cout << iter->first << (iter++)->second;   // drop  << endl for simplicity of discussion

可能会扩展为

operator<<(operator<<(std::cout << iter->first), (iter++)->second);

函数参数的求值顺序也未指定。因此在将 operator<<(std::cout << iter->first)(iter++)->second) 传递给 operator<<().

的最外层调用之前评估它们的顺序

您的编译器恰好会在 operator<<(std::cout << iter->first) 之前计算 (iter++)->second),即使您期望相反。

解决方案是不要在一个语句中混合太多具有副作用的操作,因为这是解决此类排序问题的好方法。在您的情况下,执行输出,并在下一条语句中递增 iter

cout << iter->first << iter->second << endl;
++iter;