Russian Qt Forum
Ноябрь 25, 2024, 07:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: smart pointer in Qt  (Прочитано 6561 раз)
vorotislav
Гость
« : Сентябрь 02, 2015, 14:12 »

Доброго времени суток.

Прочитал про умные указатели, захотел их освоить.
Начал в проекте пробовать перевести указатели на shared_ptr и unique_ptr
в pro-файле:
CONFIG += c++14
QMAKE_CXXFLAGS += -std=c++11

включил заголовочный файл <memory>
Код:
    std::unique_ptr<DialogInfoUser> dialog (new DialogInfoUser (this));
    dialog. ??? тут нет метода exec()

Пробовал заменить на shared_ptr - тоже самое.
Как мне вызвать метод? Что я делаю не так?
Пробовал в pro файле писать
CONFIG += c++11
QMAKE_CXXFLAGS += -std=c++0х
результат тот же.
P.S.
Qt 5.5, MinGw 4.9.2, Win7.
P.P.S
Возможно в проектах на Qt не следует пользоваться std::shared_ptr, а взяться за QSharedPointer?
Но при беглом прочтении про QSharedPointer, а так же при попытке обернуть указатель, то я так же не могу сразу достучаться до методов, только через .data()

если использовать shared:
Код:
    std::shared_ptr<DialogInfoUser> dialog (new DialogInfoUser (this));
    dialog.get()->exec(); //

То вот таким способом метод доступен. Но является ли это правильным использованием? И почему в таком случае через get() не доступен при unique_ptr?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Сентябрь 02, 2015, 14:49 »

Писать просто dialog->exec(); (во всех случаях). Ну или др метод вместо exec

Возможно в проектах на Qt не следует пользоваться std::shared_ptr, а взяться за QSharedPointer?
Для начала присмотритесь к QPointer, очень полезная вещь, пусть не смущает что работает только для QObject. Здесь важно что QPointer понимается модулями Qt, а вот др "шары" нет. Пример
Код
C++ (Qt)
{
QPointer <QLabel> lab1(new QLabel("Lab1", parent));  
QSharedPointer <QLabel> lab2(new QLabel("Lab2", parent));   // или std::shared_ptr
.... // чего-то делаем
if (!lab1.isNull()) lab1->setText("End");
if (!lab2.isNull()) lab2->setText("End");
}  // здесь оба lab1 и lab2 будут удалены (если еще не были)
 
QPointer отработает железно, а вот QSharedPointer хз. Если напр был удален сам parent - он вызовет удаление указателя сидящего в lab2, а это разрушит QSharedPointer.

В общем, не слишком рвитесь вперед  Улыбающийся 
Записан
Tuxford
Гость
« Ответ #2 : Сентябрь 02, 2015, 15:00 »

Возможно в проектах на Qt не следует пользоваться std::shared_ptr, а взяться за QSharedPointer?
Но при беглом прочтении про QSharedPointer, а так же при попытке обернуть указатель, то я так же не могу сразу достучаться до методов, только через аким
От части да. Это касается всякой гуйни. Сама архитектура Qt такая интересная. Когда занимался написание UI, то вообще старался не делать никаких динамических выделений. Кора была написана без Qt. Очень не хотелось влазить в этот Qtшных хлам.
Записан
KrupaKarlo
Гость
« Ответ #3 : Сентябрь 02, 2015, 15:42 »

Код:
 std::unique_ptr<DialogInfoUser> dialog (new DialogInfoUser (this));

Данный код уже не верен. Смысл smart pointer в том, чтобы не управлять вручную временем жизни объекта.  А тут
Код:
new DialogInfoUser (this)
вы говорите, что родитель управляет временем жизни объекта. получается один раз ваш объект попытается уничтожить родитель, а второй раз std::unique_ptr.

В обычной ситуации не надо использовать get() или data(). Они нужны, когда требуется голый указатель но объект(к примеру для создания коннекта сигнала). Обычно просто пишите  dialog->exec(); //
« Последнее редактирование: Сентябрь 02, 2015, 15:51 от KrupaKarlo » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Сентябрь 02, 2015, 16:47 »

Данный код уже не верен. Смысл smart pointer в том, чтобы не управлять вручную временем жизни объекта.  А тут
Код:
new DialogInfoUser (this)
вы говорите, что родитель управляет временем жизни объекта. получается один раз ваш объект попытается уничтожить родитель, а второй раз std::unique_ptr.

Это не всегда неверно. Например, если объект создается в ф-ии, из к-ой он возвращается по рав птру/юнику, но к-ая может тровнуть. В случае трова логично удалить объект - заворачиваем в юник/скопед поинтер.
Более конктерный пример - QDialog *createDialog(QWidget *parent = nullptr)
Записан
KrupaKarlo
Гость
« Ответ #5 : Сентябрь 02, 2015, 18:43 »

тут приведен конкретный пример, когда это неверно. Надо четко понимать кто и что у вас удаляет.
Записан
vorotislav
Гость
« Ответ #6 : Сентябрь 02, 2015, 21:35 »

KrupaKarlo, ок, я согласен с тем, что за удалением объекта следит родитель. Но если предположим, программа 24/7, она не выключается. Главное окно не выключается, значит и этот объект не удаляется? А если это окно настроек, и раз в день его открывают? Так и будет выделяться память и не освобождаться, или я чего то не понимаю?

Касаемо темы и моего главного вопроса, оказывается все просто. А не один раз видел ответ, и здесь он сразу был все дело в dialog->exec(); но я слишком быстро привык, что creator умеет менять "." на "->" когда это надо. Поэтому писал всегда "dialog." а дальше он сам. В случае с умным указателем такого не происходило, автозамены не было, не было метода exec. Я думал что все не работает. Всем большое спасибо.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #7 : Сентябрь 02, 2015, 21:42 »

Так и будет выделяться память и не освобождаться, или я чего то не понимаю?
Именно так и будет, память разом освоболится только при завершении программы (при разрушении главного окна). Это 100% утечка памяти.
Записан
KrupaKarlo
Гость
« Ответ #8 : Сентябрь 03, 2015, 09:39 »

Ненадо просто временные объекты делать через new без надобности.

К примеру если вам нужен диалог не надо его создавать в конструкторе и хранить пока программа не сдохнет. делайте так
Код:
void func(){
     MyDialog dlg;
     if(dlg.exec() == "что вас интересует")
     {
        //TODO
     }
}
В такому случае ваш диалог уничтожится сам по окончании функции
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #9 : Сентябрь 03, 2015, 12:14 »

KrupaKarlo
Я уже приводил пример.

Код:
QMenu *Widget::createDefaultMenu()
{
    QScopedPointer<QMenu> menu(new QMenu);
    menu->addAction(tr("Cool action")); // can throw
    return menu.take();
}

void Window::contextMenuEvent(QContextMenuEvent *event)
{
    QScopedPointer<QMenu> menu(widget->createDefaultMenu());
    menu->addAction(tr("Even cooler action")); // can throw
    menu->exec(event->pos());
}

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Сентябрь 03, 2015, 12:29 »

Код:
    menu->addAction(tr("Cool action")); // can throw
Ага, оказывается "тровнуть" - это throw  Улыбающийся Но пример неудачен. Слабо верится что addAction может выбросить исключение, а если это уж произойдет то не видно что должен с ним делать обработчик "наверху", поэтому try/catch должен быть здесь же
Записан
KrupaKarlo
Гость
« Ответ #11 : Сентябрь 03, 2015, 14:51 »

KrupaKarlo
Я уже приводил пример.

Код:
QMenu *Widget::createDefaultMenu()
{
    QScopedPointer<QMenu> menu(new QMenu);
    menu->addAction(tr("Cool action")); // can throw
    return menu.take();
}

void Window::contextMenuEvent(QContextMenuEvent *event)
{
    QScopedPointer<QMenu> menu(widget->createDefaultMenu());
    menu->addAction(tr("Even cooler action")); // can throw
    menu->exec(event->pos());
}



Вы создаете меню зачем то через new оборачиваете все это в smart pointer. Если вам кажется что это тоже самое что на стеке создать объект и он сам сдохнет то ок

Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #12 : Сентябрь 04, 2015, 10:29 »

Вы создаете меню зачем то через new оборачиваете все это в smart pointer. Если вам кажется что это тоже самое что на стеке создать объект и он сам сдохнет то ок

Facepalm. Может быть, для того, чтобы вернуть из функции? Если вы не заметили, Widget и Window - разные классы. Как я на стеке в Window создам меню из Widget?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.074 секунд. Запросов: 22.