[英]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 ++)->第二。
您应该将iter ++放在下一行。
您面临的问题是可以通过多种方式对其进行评估。 问题是每个 operator<<
可以先评估左侧,然后评估右侧,反之亦然。 并且由于您有三个,因此有很多变体。
现在,您尝试使用一次iter
,并在一条语句中对其进行修改,而无需进行任何排序 。 这使其成为未定义行为。 可能发生任何事情。
修正:使用两个语句。 语句以明显的顺序排序。
给出的形式的表达a << b
, a
和b
必须都被评估,但它们的计算顺序是不确定的,这意味着任何顺序被允许( 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
语句中增加iter
。
cout << iter->first << iter->second << endl;
++iter;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.