Why Are All List's Being Populated

2019-09-10 11:32发布

So given the definitions:

typedef char Task;

struct Tache {
    char step;
    int duration;
    list<Task> precedentTask;
};

I've written an extraction operator for Tache:

istream& operator>>(istream& lhs, Tache& rhs) {
    string line;

    getline(lhs, line, '\n');

    stringstream ss(line);

    ss >> rhs.step;
    ss.ignore(numeric_limits<streamsize>::max(), '(');
    ss >> rhs.duration;
    ss.ignore(numeric_limits<streamsize>::max(), ')');

    const regex re("\\s*,\\s*([a-zA-Z])");
    string precedentTasks;

    getline(ss, precedentTasks);

    transform(sregex_token_iterator(cbegin(precedentTasks), cend(precedentTasks), re, 1), sregex_token_iterator(), back_insert_iterator<list<Task>>(rhs.precedentTask), [](const string& i) {
        return i.front();
    });

    return lhs;
}

However when I try to use this extraction operator with an istream_iterator the precedentTask member seems to bleed into the next element. For example, given:

stringstream seq("A(3)\nB(4),A\nC(2),A\nE(5),A\nG(3),A\nJ(8),B,H\nH(7),C,E,G\nI(6),G\nF(5),H");

list<Tache> allTaches{ istream_iterator<Tache>(seq), istream_iterator<Tache>() };

for (const auto& i : allTaches) {
    cout << i.step << ' ' << i.duration << ' ';
    copy(cbegin(i.precedentTask), cend(i.precedentTask), ostream_iterator<Task>(cout, " "));
    cout << endl;
}

Live Example

I am getting:

A 3
B 4 A
C 2 A A
E 5 A A A
G 3 A A A A
J 8 A A A A B H
H 7 A A A A B H C E G
I 6 A A A A B H C E G G
F 5 A A A A B H C E G G H

Rather than my expected:

A 3
B 4 A
C 2 A
E 5 A
G 3 A
J 8 B H
H 7 C E G
I 6 G
F 5 H

Am I misusing the sregex_token_iterator?

1条回答
时光不老,我们不散
2楼-- · 2019-09-10 11:56

This has nothing to do with regex and everything to do with what istream_iterator does under the hood: it only has one T element that it will read into when you increment it:

istream_iterator& operator++();
3 Requires: in_stream != 0.
4 Effects: *in_stream >> value.
5 Returns: *this.

Your stream operator is just appending to rhs.precedentTask, but it's not necessarily empty to start with. Just clear it first. This isn't an istream_iterator problem either, your operator>> has to be able to work in this situation too:

Tache foo;
while (std::cin >> foo) {
    // ...
}

If all you're doing is appending, then every subsequent Tache after the first one will be wrong. You are completely responsible for initializing all of the members of the object and you should make no assumptions about their previous values.


I'd recommend substituting transform() for just a loop:

sregex_token_iterator it(cbegin(precedentTasks), cend(precedentTasks), re, 1), end;
for (; it != end; ++it) {
    rhs.precedentTask.push_back(it->front());
}

or wrapping that in a range:

for (std::string match : sregex_matches(precedentTasks, re, 1)) {
    rhs.precedentTask.push_back(match.front());
}
查看更多
登录 后发表回答