segmentation fault при выводе словаря set

169
24 ноября 2018, 07:20

Решаю небольшую задачку на тему словарей. Писал подульно, чтобы было можно сразу найти ошибки. Стал тестировать. В некоторых случаях выдаётся ошибка при вызове функии Print. Суть блока кода такая. Есть некий словарь словарей строк. В нём сейчас имеется некоторое количество элементов. На вход подаётся 2 строки, если первая строка есть, тогда создаётся временная переменная, в которой дабавляются все значения что были в этом элементе словаря. Затем удаляется этот элемент словаря и добавляется новый. Если в элементе словаря только 3 элемента или меньше, ошибка на первое добавление не срабатывает и всё выводится. При следующем добавлении, уже вылетает данная ошибка. Никак не пойму в чём дело...

void PrintSet(const set <string> &vectStr){
    for(auto s: vectStr){
        cout << s << endl;
    }
}
void Print(const set<set<string>> &input){
    for(auto s : input){
        PrintSet(s);
    }
}
//проверка есть ли элемент в словаре
bool FindInSet(const set<string> &setStr, const string &inputWord){
    return setStr.count(inputWord);
}
//ADD word1 word2 — добавить в словарь пару синонимов (word1, word2)
void Add(set<set<string>> &input){
    string word1, word2;
    cin >> word1 >> word2;
    set <string> words;
    words.insert(word1);
    words.insert(word2);
    set <string> tmp;
    bool check = false;// нет в словаре
    for(auto s :input){
        if(FindInSet(s, word1)){
            tmp = s;
            for(auto add : words){
                tmp.insert(add);
            }
            input.erase(s);
            input.insert(tmp);
            check = true;
        }
    }
    if(check == false){
        input.insert(words);
    }
}
int main() {
    set<string> test = {"word", "words", "worde", "wow", "wwooccwoowo", "woccw", "wwccoowoowo"};
    set<set <string>> test1;
    test1.insert(test);
    Add(test1);
    //Add(test1);
    cout << "end" <<endl;
    Print(test1);
    return 0;
}
Answer 1
for (auto s :input){
  ...
  input.erase(s);
  ...
}

Вы удаляете из input текущий итерируемый элемент контейнера. После этого поведение не определено. Все падает.

Range-based for цикл не является каким-то "волшебным" циклом, в котором можно делать что угодно. Range-based for - это не более чем "синтаксический сахар" для обыкновенного цикла с итератором. Этот итератор просто скрыт от ваших глаз. Уничтожив текущий элемент контейнера, вы сделали этот внутренний итератор невалидным. Далее все накрылось.

Не надо пользоваться range-based for в ситуациях, когда вы собираетесь модифицировать итерируемый контейнер.

P.S. У вас передача параметров везде выписана "по ссылке", чтобы избежать создания копий, а итерирование везде тупо делается по значению, создавая на каждой итерации никому не нужные копии "тяжелых" объектов. Раз уж вы умеете передавать аргументы по ссылке, то и итерировать, наверное, по ссылке должны уметь?

READ ALSO
в чем отличие виртуальной функции от шаблонной функции?

в чем отличие виртуальной функции от шаблонной функции?

Подскажите пожалуйста, чем отличается виртуальная функция от шаблонной функции?

150
Как узнать формат даты?

Как узнать формат даты?

Как узнать формат даты, если он неизвестен заранее?

148