Умные указатели в С++(Qt)

291
28 марта 2018, 05:53

Здравствуйте, недавано познакомился с Qt, но визникли некоторые проблемы по поводу использования умных указателей вместес QTableView, вот пример кода:

MainFormSettings::MainFormSettings(Ui::MainForm* mainForm) {
    ui = mainForm;
    administratorsService = new AdministratorsService;
    modelAdministrators = new QStandardItemModel;
    QStringList headers;
    headers.append("Логин");
    headers.append("Пароль");
    modelAdministrators->setHorizontalHeaderLabels(headers);
    ui->tableAdministrators->setModel(modelAdministrators);
    QMap<QString, QString> administrators = administratorsService->getAllAdministrators();
    size_t row = 0;
    for (auto it = administrators.begin(); it != administrators.end(); it++) {
        QString login = it.key();
        QString password = it.value();
        QStandardItem* itemLogin = new QStandardItem(login);
        modelAdministrators->setItem(row, 0, itemLogin);
        QStandardItem* itemPassword = new QStandardItem(password);
        modelAdministrators->setItem(row, 1, itemPassword);
        row++;
    }
}

Так все прекрасно работает. Как видно из кода заполняю таблицу администраторов(лоиг и пароль) из базы данных, но потом при перезагрузки таблицы новыйми данными память же придется освободить, в связи с этим решил воспользоваться умными указателями:

MainFormSettings::MainFormSettings(Ui::MainForm* mainForm) {
    ui = mainForm;
    administratorsService = new AdministratorsService;
    modelAdministrators = new QStandardItemModel;
    QStringList headers;
    headers.append("Логин");
    headers.append("Пароль");
    modelAdministrators->setHorizontalHeaderLabels(headers);
    ui->tableAdministrators->setModel(modelAdministrators);
    QMap<QString, QString> administrators = administratorsService->getAllAdministrators();
    size_t row = 0;
    for (auto it = administrators.begin(); it != administrators.end(); it++) {
        QString login = it.key();
        QString password = it.value();
        std::unique_ptr<QStandardItem> itemLogin = std::make_unique<QStandardItem>(login);
        modelAdministrators->setItem(row, 0, itemLogin.get());
        std::unique_ptr<QStandardItem> itemPassword = std::make_unique<QStandardItem>(password);
        modelAdministrators->setItem(row, 1, itemPassword.get());
        row++;
    }
}

Но когда я использую это, просто в таблицу ничего не выводится, по видимому память освобождается... Может кто-ниубдь подскажет в чем проблема и способ ее решения? Заранее спасибо

Answer 1

Используемый вами тип QStandardItemModel сам освободит в своем деструкторе все лежащие в нем объекты когда придет время; дополнительно освобождать что бы то ни было не только бесполезно, но и ошибочно.

Использовать unique_ptr для хранения промежуточных объектов можно - но только в более сложных случаях, когда вы не сразу передаете владение ими в другой класс. Для этого можно использовать метод release:

std::unique_ptr<QStandardItem> itemLogin = std::make_unique<QStandardItem>(login);
// ...
modelAdministrators->setItem(row, 0, itemLogin.release());

Но в вашем случае это избыточно, ведь между созданием объекта и добавлением его в modelAdministrators нет никакого лишнего кода.

Где и правда следует применять умные указатели - так это в вашем классе, для того чтобы автоматически освободить QStandardItemModel:

private:
std::unique_ptr<QStandardItemModel> modelAdministrators;
Answer 2

В данном случае Вам не нужны умные указатели: когда вы добавляете QStandardItem в модель, то уже модель отвечает за удаление своих элементов.

В случае с std::unique_ptr, вы добавляете в модель указатель на данные, затем область видимости std::unique_ptr заканчивается и указатель удаляется, модель в с свою очередь видит что элемент удален и по-этому не использует его для отображения.

Answer 3

Qt и стандартные умные указатели обычно не совместимы. В данном случае метод setItem принимает владение объектом, на который указывает переданный указатель. В других случаях могут применяться умные указатели qt.

READ ALSO
Segmentation fault при разыменовании

Segmentation fault при разыменовании

Что я делаю не так?:

201
Задать дефолтное значение для Singleton

Задать дефолтное значение для Singleton

Имеется класс-синглтон для покрытия тестами используя gmock frameworkНекоторые методы (как например method1() в примере) изменяют значения полей класса...

202
Удаление Item&#39;a QGraphicsScene C++

Удаление Item'a QGraphicsScene C++

Вопрос заключается в следующем - инициализировал QGraphicsEllipseItem *ellipse и обозначил его на QGraphicsScene, как корректно будет удалить этот эллипс со сцены?

203
На чем написать MMO игровой сервер? (по типу (agar.io)

На чем написать MMO игровой сервер? (по типу (agar.io)

Хочу сделать браузерную игру по типу ИО-игр (agario, slither

194