繁体   English   中英

istream_iterator不会零初始化

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM