[英]istream_iterator Does Not Zero-Initialize
这是一个最小的,完整的,可验证的示例,我了解这并非是无效的。 无论如何,鉴于结构:
struct Foo {
int even;
int odd;
};
istream& operator>>(istream& lhs, Foo& rhs) {
int input;
lhs >> input;
(input % 2 == 0 ? rhs.even : rhs.odd) = input;
return lhs;
}
我可以执行以下操作:
stringstream bar("1 2 3 4 5 6 7 8 9 0");
for (const auto& i : vector<Foo>{istream_iterator<Foo>(bar), istream_iterator<Foo>()}) {
cout << i.even << ' ' << i.odd << endl;
}
但这给了我结果:
-1215720516 1
2 1
2 3
4 3
4 5
6 5
6 7
8 7
8 9
0 9
要对Foo
零初始化,我可以编写代码:
for(Foo i{}; bar >> i; i = Foo{}) {
cout << i.even << ' ' << i.odd << endl;
}
这给了我我期望的结果:
0 1
2 0
0 3
4 0
0 5
6 0
0 7
8 0
0 9
0 0
我知道使用提取运算符不能完全覆盖变量是很困难的。 这最初是由我在这里的回答和我在这里的问题引起的,在我看来,我的问题更自然地期望将读取之间的变量零初始化。 在任何情况下,是否都可以使用istream_iterator
以便在istream_iterator
读取之间将变量初始化为零,还是必须使用for
-loop?
我心中更自然地期望将读取之间的变量零初始化
那是一个不正确的期望。 operator>>
应该彻底和初始化对象负责 。 您不能假定该对象先前已被默认/值初始化。 一个很标准的用例是在while循环中读取所有对象:
Foo foo;
while (std::cin >> foo) { ... }
第二次, foo
将具有任何旧值-这里没有任何零值。 因此,您需要确保当操作员返回时,新对象完全由您设置。
最简单的事情是首先对其进行值初始化:
istream& operator>>(istream& lhs, Foo& rhs) {
int input;
lhs >> input;
rhs = Foo{}; // <== add this
input % 2 == 0 ? rhs.even : rhs.odd) = input;
return lhs;
}
或者,您可以手动编写两个:
if (input % 2 == 0) {
rhs.odd = 0;
rhs.even = input;
}
else {
rhs.odd = input;
rhs.even = 0;
}
或汇总初始化每种情况:
rhs = input % 2 == 0 ? Foo{input, 0} : Foo{0, input};
无论如何, operator>>
负责将要清零的值清零。
是否可以使用istream_iterator使得变量在两次读取之间初始化为零?
如果查看istream_iterator的内部,则它具有以下内部状态。
private:
istream_type* _M_stream;
_Tp _M_value;
bool _M_ok;
其中_M_value是默认构造的。
当使用++ / ++时,它将调用_M_read(),其实现中具有以下相关行。
*_M_stream >> _M_value;
因此,迭代器本身永远不会在Extrator之外触及Foo的状态,并且_M_value
在_M_value
调用之间被重用。 也就是说,您需要自己以某种方式对其进行初始化。 我认为在operator>>
是一个合理的地方。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.