sharedptr C++(падает программа)

238
06 января 2018, 03:21

Здравствуйте, использую в программе std::shared_ptr и программа начинает себя вести по странному. У меня программа БД для школы и вот при добавлении к примеру нового ученика она может, как корректно отработать так и упасть. Вот листинг добавления ученика:

Модель ученика staff.h / staff.cpp

class Pupil : public Models
{
private:
     QString name;
     QString dateOfBirth;
     QString phoneNumber;
     QString personalData;
     QString address;
     QString hisClass;
     Pupil(QString &name, QString &dateOfBirth, QString &phoneNumber,
           QString &personalData, QString &address, QString &hisClass);
public:
    class Builder {
        QString name;
        QString dateOfBirth;
        QString phoneNumber;
        QString personalData;
        QString address;
        QString hisClass;
    public:
        Builder& setName(QString name);
        // Setters ...
        Pupil* build();
    };
    QString getPhoneNumber() const;
    // Getters ...
};
...
// Здесь происходит выделение через умный указатель
Pupil *Pupil::Builder::build()
{
    std::shared_ptr<Pupil> newPupil(new Pupil(name, dateOfBirth, phoneNumber, personalData, address, hisClass));
    return newPupil.get();
}
...

Форма для работы с учениками pupils_form.h. / pupils_form.сзз

...
void PupilsForm::clickedBtnAddPupil()
{
    AddPupilDialog addPupilDialog;
    if(addPupilDialog.exec() == QDialog::Accepted)
    {
        Pupil *pupil = addPupilDialog.getData();
        pupilsModel->addItem(pupil);
    }
}   
...

Диалог для добавления ученика add_pupil_dialog.h / add_pupil_dialog.cpp

...
Pupil *AddPupilDialog::getData()
{
     Pupil *pupil = Pupil::Builder()
           .setName(ui->edtName->text())
           .setNumber(ui->edtPhoneNumber->text())
           .setAddress(ui->edtAddress->text())
           .setDateOfBirth(ui->edtDateOfBirth->text())
           .setPersonalData(ui->edtPersonalData->text())
           .setHisClass(ui->cbxClass->currentText())
           .build();
    return pupil;
}
...

Класс для работы с моделью ученика pupils_model.h / pupils_model.cpp

...    
void PupilsModel::addItem(Models *item)
{
    Pupil *pupil = (Pupil*)item;
    //Prepare for execute the query
    QMap<QString, QString> prepareQuery;
    prepareQuery.insert(":name", pupil->getName());
    prepareQuery.insert(":number", pupil->getPhoneNumber());
    prepareQuery.insert(":address", pupil->getAddress());
    prepareQuery.insert(":personalData", pupil->getPersonalData());
    prepareQuery.insert(":dateOfBirth", pupil->getDateOfBirth());
    prepareQuery.insert(":class", pupil->getHisClass());
    // Здесь программа не падает, выдает корректное ФИО ученика
    qDebug() << pupil->getName();
    //Executing the query
    QString query = "INSERT INTO pupils(name, data_birth, person_data, number, address, id_class)"
                "VALUES(:name, :dateOfBirth, :personalData, :number, :address, "
                "(SELECT c.id FROM classses c WHERE c.name = :class))";
    dataBase->execInsert(query, prepareQuery);
 }
 ...

Класс для работы с БД database.h / database.cpp

void DataBase::execInsert(QString &stringQuery, QMap<QString, QString> &prepareQuery)
{
    QSqlQuery query;
    query.prepare(stringQuery);
    for(auto it = prepareQuery.begin(); it != prepareQuery.end(); it++)
    {
        query.bindValue(it.key(), it.value());
    }
    // А вот здесь как раз таки она иногда и падает с map не читаются данные
    qDebug() << prepareQuery.first();
    query.exec();
    checkSuccessRequest(query);
}

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

Answer 1

Не буду копаться и ковыряться везде, скажу только об этом:

// Здесь происходит выделение через умный указатель
Pupil *Pupil::Builder::build()
{
    std::shared_ptr<Pupil> newPupil(new Pupil(name, dateOfBirth, phoneNumber, 
                                              personalData, address, hisClass));
    return newPupil.get();
}

Итак, создаем локальный shared_ptr (зачем?), который на выходе из функции удаляет переданный ему объект в динамической памяти и освобождает память. Так что возвращается указатель на уже освобожденную память. Чистой воды UB.

Уж лучше б вы просто писали

Pupil *Pupil::Builder::build()
{
    return new Pupil(name, dateOfBirth, phoneNumber, 
                     personalData, address, hisClass));
}

или

std::shared_ptr<Pupil> Pupil::Builder::build()
{
    std::shared_ptr<Pupil> newPupil(new Pupil(name, dateOfBirth, phoneNumber, 
                                              personalData, address, hisClass));
    return newPupil;
}

Дальше просто не смотрел, этого уже вполне достаточно...

READ ALSO
задачи на палиндромы

задачи на палиндромы

В первой строке входных данных содержится число N (1 <= N <= 100000)Во второй строке задается последовательность из N больших латинских букв (буквы...

219
Выбор кандидатов при вызове функций

Выбор кандидатов при вызове функций

Почему в следующем коде std::swap не рассматривается в качестве кандидата при вызове swap и приходится писать его полностью с пространством имён?...

231
Рефакторинг кода в Qt (C++)

Рефакторинг кода в Qt (C++)

Здравствуйте, задался довольно-таки очень простым вопросом

553
Приведение типов умных указателей C++

Приведение типов умных указателей C++

А можно ли привести тип умного указателя родительского класса к дочернему? К примеру есть есть базовый класс Models и от него наследуется класс...

297