【问题标题】:Why Are All List's Being Populated为什么所有列表都被填充
【发布时间】:2016-10-06 12:29:18
【问题描述】:

所以给出定义:

typedef char Task;

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

我为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;
}

但是,当我尝试将此提取运算符与 istream_iterator 一起使用时,precedentTask 成员似乎会渗入下一个元素。例如,给定:

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

我得到:

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
我 6 A A A A B H C E G G
F 5 A A A A B H C E G G H

而不是我的预期:

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

我是否误用了sregex_token_iterator

【问题讨论】:

    标签: c++ regex list iterator istream-iterator


    【解决方案1】:

    这与正则表达式无关,而与 istream_iterator 在后台所做的一切有关:它只有一个 T 元素,当您增加它时它会读入:

    istream_iterator&amp; operator++();
    3 需要in_stream != 0
    4 效果*in_stream &gt;&gt; value.
    5 返回*this.

    您的流操作符只是附加到rhs.precedentTask,但它不一定是空的。先把它清除掉。这也不是istream_iterator 问题,您的operator&gt;&gt; 也必须能够在这种情况下工作:

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

    如果您所做的只是追加,那么在第一个Tache 之后的每个Tache 都将是错误的。你完全负责初始化对象的所有成员,你不应该对它们以前的值做任何假设。


    我建议将 transform() 替换为一个循环:

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

    或将其包装在一个范围内:

    for (std::string match : sregex_matches(precedentTasks, re, 1)) {
        rhs.precedentTask.push_back(match.front());
    }
    

    【讨论】:

    • 呃...清除它工作,但我完全没有解释为什么。 rhs.precedentTaskprecedentTask not 怎么会使用空元素?您是说,如果我只编写提取运算符来提取对象的某些成员,我很可能会得到非零初始化成员 x.x
    • @JonathanMee 详细说明了答案。是的,当然。
    • 我希望能更详细地了解可能的解决方法,所以我在这里打开了一个链接问题:stackoverflow.com/q/37682156/2642059
    猜你喜欢
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 2015-10-03
    • 1970-01-01
    相关资源
    最近更新 更多