Why Are All List's Being Populated

偶尔善良 提交于 2019-12-25 03:56:30

问题


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:


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());
}


来源:https://stackoverflow.com/questions/37665206/why-are-all-lists-being-populated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!