对this答复的评论指出,不应使用以下代码,因为它表现出未定义的行为:
int old = (std::cin >> old, old);
here也非常鄙视类似的代码,尤其是表现出未定义的行为。
另一方面,极受好评的this则建议使用以下代码作为逗号运算符的实用性示例:
while (cin >> str, str != "STOP") {
//process str
}
我假设如果此代码表现出未定义的行为,则不会被投票。
问题:如果第一个代码是未定义的行为(大概是由于使用了cin
的读取结果而未检查后者的状态),那么第二个代码为什么会这样精细?
编辑:第一个示例的评论部分回答了问题。第二个示例未显示的是str
是std::string
的实例,因此已初始化。因此,没有未定义的行为。
答案 0 :(得分:5)
由于C ++ 11 假定读取了非空白字符,因此语句int old = (std::cin >> old, old);
定义明确。这是因为如果在这种情况下old
失败,则std::cin
会设置为零。使用表达式分隔符运算符,
也是合法的,因为它可以对表达式std::cin >> old
和old
进行排序。如果没有非空白字符被计数,那么old
仍不会被std::cin >> old
更改,并且代码的行为是不确定的。
假设str
是std::string
类型,则(cin >> str, str != "STOP")
始终是
定义明确的如果cin >> str
失败,则保留str
的初始值(可能是默认构造的),然后,
再次对表达式进行排序。
答案 1 :(得分:2)
两个答案都是错误答案,但只有第一个答案可能会表现出不确定的行为。
int old = (std::cin >> old, old);
当std::cin >> old
失败时,old
可以具有它的值。因此它可以保留为未初始化的int
,因此从中读取是未定义的行为。
while (cin >> str, str != "STOP") { //process str }
当cin >> str
失败时,str
将具有其先前的值。假设str
为std::string
,则它不能具有与聚合类型不同的未初始化状态。因此它将具有其先前的值,例如默认构造的值""
或先前读取的值"MOP"
。从中读取并与"STOP"
进行比较从来都不是未定义的行为。但是,cin >> str
很可能会在下一个周期再次失败,因此str永远不会是"STOP"
,因此它将是无穷循环,所以&&
is likely better than comma there。
另外,值得注意的是,当我们尝试结合第一个示例和第二个示例时,我们can get real crash:
std::string old = (std::cin >> old, old);
如果未将流设置为引发故障,那么我们应该手动检查那些状态(并且std::cin
并不特殊),因为这些状态可能会终止并发生故障。不幸的是,许多教程示例都没有做到这一点。因此,有些人似乎认为流操作适合使用逗号运算符插入某些表达式的中间。
编辑:
我不确定评论是否与C ++ 11不同。挖了,但找不到标准的确认。在出现错误的情况下,使用g ++尝试此代码不会读取零:
#include <iostream>
#include <sstream>
int main()
{
std::stringstream in("42");
int i = 0;
std::cout << i << '\n'; // outputs 0
in >> i;
std::cout << i << '\n'; // outputs 42
i = 666;
in >> i;
std::cout << i << '\n'; // outputs 666
// so it did leave value of i like it was
}
Demo。也以任何方式std::cin does not seem special。当然,可能是g ++的实现不正确,或者仅在失败子集的情况下才需要失败的输入来设置i
,因此第一个示例仍可能表现出不确定的行为。