3

这是一个最小的、完整的、可验证的示例我知道这不是共产主义。无论如何,给定结构:

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

我知道拥有一个不完全覆盖变量的提取运算符是粗略的。这最初源于我在此处的回答此处的问题,在我看来,我更自然地期望在读取之间对变量进行零初始化。在任何情况下,是否可以使用这样的变量在读取之间初始化为零,或者我必须使用-loop?istream_iteratorfor

4

2 回答 2

3

在我的脑海中,更自然地期望在读取之间对变量进行零初始化

这是一个错误的期望。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>>负责将您想要归零的值归零。

于 2016-06-07T15:59:33.150 回答
1

是否可以使用 istream_iterator 使变量在读取之间初始化为零?

如果您查看istream_iterator 的内部,它具有以下内部状态。

private:
  istream_type* _M_stream;
  _Tp       _M_value;
  bool      _M_ok;

其中 _M_value 是默认构造的。

当使用 it++/++it 时,它会调用 _M_read() ,它的实现中有以下相关行。

*_M_stream >> _M_value;

因此,迭代器本身永远不会在提取器之外触及 Foo 的状态,并_M_value在调用之间重用。即您需要自己以某种方式对其进行初始化。我认为operator>>是一个合理的地方。

于 2016-06-07T14:59:09.650 回答