В QHash при использовании erase() помимо удаления нужного объекта затираются данные у соседнего

Имеется QHash<int, Examiner>, данный хэш заполняется элементами, затем по нему рисуется табличка QTableWidget. Задача: по указанному пользователем номеру ряда в таблице удалить соответствующую запись из хэша и из таблицы. Проблема: по указанному ряду я получаю объект класса Examiner, затем ищу Key, соответствующий этому элементу в QHash, и удаляю с помощью erase(). Почему-то помимо удаления нужной пары ключ-значение в хэше еще у одного объекта класса Examiner затираются данные (т.е., например, строковые значения меняются на ""). При использовании remove() результат аналогичный.

Почему так происходит и как сделать так, чтобы просто удалялась нужная пара ключ-значение, а остальные не менялись?

Часть кода, где заполняется таблица и удаляется нужная пара ключ-значение:

    QHash<int, Examiner> examiners;
    examiners.insert(identificator++, Examiner(1, "Shevchenko", "Anna", "Igorevna", "916836493", "[email protected]"));
    examiners.insert(identificator++, Examiner(2, "Potapov", "Oleg", "Stepanovich", "9163789423", "[email protected]"));
    examiners.insert(identificator++, Examiner(3, "Ivanova", "Inna", "Pavlovna", "9269217654", "[email protected]"));
    examiners.insert(identificator++, Examiner(4, "Zaytcev", "Ilya", "", "9256134981", "[email protected]"));

    ui->tableWidget->setRowCount(examiners.size());
    ui->tableWidget->setColumnCount(6);
    ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "id" << "surname" << "name" << "patronymic" << "phone" << "email");

    for (int i = 0; i < ui->tableWidget->rowCount(); i++) {
        for (int j = 0; j < ui->tableWidget->columnCount(); j++) {
            switch (j) {
            case 0: {
                QTableWidgetItem *tbl = new QTableWidgetItem(QString::number(examiners.value(i).getId()));
                ui->tableWidget->setItem(i,j,tbl);
                break;
            }
            case 1: {
                QTableWidgetItem *tbl = new QTableWidgetItem(examiners.value(i).getSurname());
                ui->tableWidget->setItem(i,j,tbl);
                break;
            }
            case 2: {
                QTableWidgetItem *tbl = new QTableWidgetItem(examiners.value(i).getName());
                ui->tableWidget->setItem(i,j,tbl);
                break;
            }
            case 3: {
                QTableWidgetItem *tbl = new QTableWidgetItem(examiners.value(i).getPatronymic());
                ui->tableWidget->setItem(i,j,tbl);
                break;
            }
            case 4: {
                QTableWidgetItem *tbl = new QTableWidgetItem(examiners.value(i).getPhone());
                ui->tableWidget->setItem(i,j,tbl);
                break;
            }
            case 5: {
                QTableWidgetItem *tbl = new QTableWidgetItem(examiners.value(i).getEmail());
                ui->tableWidget->setItem(i,j,tbl);
                break;
            }
            default:
                break;

            }
        }
    }

    int row = 2;

    Examiner ex;
    for (int i = 0; i < ui->tableWidget->columnCount(); i++) {
        switch (i) {
        case 0: {
            QTableWidgetItem *tbl = ui->tableWidget->item(row,i);
            ex.setId(tbl->text().toInt());
            break;
        }
        case 1: {
            QTableWidgetItem *tbl = ui->tableWidget->item(row,i);
            ex.setSurname(tbl->text());
            break;
        }
        case 2: {
            QTableWidgetItem *tbl = ui->tableWidget->item(row,i);
            ex.setName(tbl->text());
            break;
        }
        case 3: {
            QTableWidgetItem *tbl = ui->tableWidget->item(row,i);
            ex.setPatronymic(tbl->text());
            break;
        }
        case 4: {
            QTableWidgetItem *tbl = ui->tableWidget->item(row,i);
            ex.setPhone(tbl->text());
            break;
        }
        case 5: {
            QTableWidgetItem *tbl = ui->tableWidget->item(row,i);
            ex.setEmail(tbl->text());
            break;
        }
        default: {
            break;
        }
        }

    }

   qDebug() << "Размер хеша до удаления: " << examiners.size();
   qDebug() << "Данные до удаления:";
   for (int i = 0; i < examiners.size(); i++) {
       qDebug() << examiners.value(i).getName() << " " << examiners.value(i).getSurname();
   }


    QHash<int, Examiner>::iterator i = examiners.find(examiners.key(ex));
    while (i != examiners.end() && i.key() == examiners.key(ex)) {
        qDebug() << "Имя удаляемого объекта: " << i.value().getName();
       i = examiners.erase(i);
    }

    //qDebug() << examiners.remove(examiners.key(ex));

    ui->tableWidget->removeRow(row);

    qDebug() << "Размер хеша после удаления: " << examiners.size();
    qDebug() << "Данные после удаления:";
    for (int i = 0; i < examiners.size(); i++) {
        qDebug() << examiners.value(i).getName() << " " << examiners.value(i).getSurname();
    }

Вывод в консоли:

Размер хеша до удаления:  4
Данные до удаления:
"Anna"   "Shevchenko"
"Oleg"   "Potapov"
"Inna"   "Ivanova"
"Ilya"   "Zaytcev"
Имя удаляемого объекта:  "Inna"
Размер хеша после удаления:  3
Данные после удаления:
"Anna"   "Shevchenko"
"Oleg"   "Potapov"
""   ""

Заголовочный файл класса Examiner:

#include <QString>
#ifndef EXAMINER_H
#define EXAMINER_H


class Examiner
{

    friend QDataStream& operator>>(QDataStream& out, Examiner& examiner);

private:
    int id;
    QString surname;
    QString name;
    QString patronymic;
    QString phone;
    QString email;


public:

    Examiner(): id(0), surname(""), name(""), patronymic(""), phone(""), email("") { };

    Examiner(int id, QString surname, QString name, QString patronymic, QString phone, QString email)
    {
        this->id = id;
        this->surname = surname;
        this->name = name;
        this->patronymic = patronymic;
        this->phone = phone;
        this->email = email;
    }

    int getId() {
        return this->id;
    }

    QString getSurname() {
        return this->surname;
    }

    QString getName() {
        return this->name;
    }

    QString getPatronymic() {
        return this->patronymic;
    }

    QString getPhone() {
        return this->phone;
    }

    QString getEmail() {
        return this->email;
    }

    void setId(int id) {
        this->id = id;
    }

    void setSurname(QString s) {
        this->surname = s;
    }

    void setName(QString n) {
        this->name = n;
    }

    void setPatronymic(QString p) {
        this->patronymic = p;
    }

    void setPhone(QString ph) {
        this->phone = ph;
    }

    void setEmail(QString e) {
        this->email = e;
    }

    friend bool operator== (const Examiner& ex1, const Examiner& ex2) {
        return (ex1.id == ex2.id && ex1.surname == ex2.surname && ex1.name == ex2.name && ex1.patronymic == ex2.patronymic
                && ex1.phone == ex2.phone && ex1.email == ex2.email);

    }


};


#endif // EXAMINER_H

Ответы (1 шт):

Автор решения: Bearded Beaver

У вас не затираются другие данные, вы просто не то выводите. QHash это ассоциативная таблица "ключ-значение", когда вы делаете insert, вы вставляете пары таких значений. Inna Ivanova, которую вы удаляете, идет в хеше под ключом 2, судя по всему. После удаления ключи у вас становятся 0, 1, 3 (2 вы удалили). Длина таблицы 3, поэтому вы запрашиваете данные по ключам 0, 1, 2. 2 у вас удаленный, а до 3 вы не добрались, поэтому он у вас не выводится.

По ассоциативным массивам итерируются не так, как вы, а примерно вот так:

for (auto i = examiners.begin(); i != examiners.end(); ++i)
    qDebug() << i.key() << i.value().getName();

Также надо заметить, что у вас теряется смысл использования ассоциативного массива, потому что вы все равно делаете поиск по значению. В такой ситуации проще использовать вектор, или же сделать ключом что-то, по чему вы можете сделать быстрый поиск, например у вас фигурирует id, который обычно хорошо подходит на роль ключа.

→ Ссылка