Problem z reverse_iteratorami + erase, program wywala się

0

Witam, nakodziłem sobie taki prosty programik przy użyciu Qt
Problem jest taki: gdy wybiore jakiś plik/pliki i dam "remove files" to program się wywala. W konsoli Qt jest napisane tylko to:

Error - RtlWerpReportException failed with status code :-1073741823. Will try to launch the process directly

02:53:32: The program has unexpectedly finished.

gui.cpp

void Gui::on_removeButton_clicked(){
    QList<QListWidgetItem*> selected = fileList->selectedItems();

    auto v = curArchive->getFiles();
    QString buffer;

    for(std::vector<FileData>::reverse_iterator it = v.rbegin(); it != v.rend(); it++){
        for(QList<QListWidgetItem*>::reverse_iterator s = selected.rbegin(); s != selected.rend(); s++){
            buffer = (*s)->text();
            int pos = buffer.indexOf('|');
            buffer = buffer.mid(pos + 2); // characer + space
            if((*it).getFilename() == buffer.toStdString()){
                curArchive->remove(std::next(it).base());
                selected.erase(std::next(s).base());
            }
        }
    }

    loadFilesList();
    updateActions(); //to tylko ustawia przyciski na wlaczone/wylaczone

    ui_saveButton->setEnabled(true);
}

void Gui::loadFilesList(){
    fileList->clear();
    auto v = curArchive->getFiles();
    QString buffer;
    for(auto& item : v){
        buffer.clear();
        buffer = QString::number(fileList->count()+1);
        buffer += ") Size: ";
        buffer += this->locale().formattedDataSize(item.getDataLength());
        buffer += " | ";
        buffer += QString::fromStdString(item.getFilename());
        fileList->addItem(buffer);
    }
}

archive.h

        std::vector<FileData> listFiles;
        const std::vector<FileData>& getFiles() const { return listFiles; }
        void remove(std::vector<FileData>::iterator iter);

archive.cpp

void Archive::remove(std::vector<FileData>::iterator iter){
    modified = true;
    listFiles.erase(iter);
}

curArchive to pointer do obecnego archiwum i jest poprawny
Jeśli trzeba coś jeszcze to podrzuce.

Troche czuje, że chyba źle sobie to poprojektowałem to, ale już dokończe tak jak jest.
Anyway, co poszło tu nie tak?

0

Czym jest v/co zwraca getFiles()? Bo jeżeli kopiujesz ten wektor to nie dziwne, że iteratory z kopii nie pasują do oryginału. No i co do:
listFiles.erase(iter);
An invalid position or range causes undefined behavior.
Co jak trafisz w v.end()?

EDIT: zignoruj drugie pytanie ;)

0
 curArchive->remove(std::next(it).base());
 selected.erase(std::next(s).base());

Co będzie jeśli `it` lub `s` będą wskazywać na ostatnie elementy?
5

Używasz erase(), a nigdzie nie używasz wartości zwracanej z tej funkcji.

https://en.cppreference.com/w/cpp/container/vector/erase

Invalidates iterators and references at or after the point of the erase, including the end() iterator.

Postaraj się użyć idiomu erase-remove zamiast tak kombinować.

0

Poczytałem troche o idiom erase-remove, doczytałem też o lambdach

Na pierwsze testy działa to. Czy nie ma tu jakiś ukrytych kruczków?

void Archive::remove(const std::string& fileToDelete){
    listFiles.erase(std::remove_if(listFiles.begin(), listFiles.end(),
                                [&](const FileData& file) { return file.getFilename() == fileToDelete; }),
                    listFiles.end());
}
    for(QList<QListWidgetItem*>::reverse_iterator s = selected.rbegin(); s != selected.rend(); s++){
        buffer = (*s)->text();
        int pos = buffer.indexOf('|');
        buffer = buffer.mid(pos + 2); // characer + space

        curArchive->remove(buffer.toStdString());
    }
1

Kruczek jest, ale go ominąłeś ( https://dev.krzaq.cc/post/an-erase-remove-idiom-gotcha/ )

Teraz wygląda to ok - o ile w drugim listingu iterujesz po innym kontenerze niż curArchive.

0

Poczekaj, a to nie jest tak, że używanie erase w pętli z iteratorem może zinwalidować Ci iteratory? W związku z czym masz UB?

0

@kq
selected to lista nijak nie powiązana z curArchive ;)

Anyway, dzięki wielkie!

1 użytkowników online, w tym zalogowanych: 0, gości: 1