Подтвердить что ты не робот

Удаление объектов по сигналам, Собственность на объекты в сигналах, Qt

Здесь мое объявление сигнала:

signals:
    void mySignal(MyClass *);

И как я его использую:

MyClass *myObject=new myClass();
emit mySignal(myObject);

Вот моя проблема: кто ответственен за удаление myObject:

  • Код отправителя, если он удаляется до использования myObject? Висячий указатель

  • Слот, подключенный к сигналу, если нет слота или более одного слота, который подключен к сигналу? Устранение утечки памяти или указатель поворота

Как Qt управляет этой ситуацией в своих встроенных сигналах? Использует ли он внутренний подсчет ссылок?

Каковы ваши лучшие практики?

4b9b3361

Ответ 1

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

  • если вы решите передать указатель в качестве параметра, тогда вы будете работать в проблемах, которые вы описываете, управления памятью - здесь никто не может работать для вас, так как вам нужно будет установить политику для решения задачи выделения/удаления. К некоторым идеям о том, как обратиться к этому, см. Правила управления памятью в COM мире.
  • Если вы решите передать параметр в качестве ссылки, вам не придется беспокоиться об управлении памятью, но только о слотах, которые неожиданно изменяют ваш объект. Идея не пропускает указатели, если вам не нужно - вместо этого используйте ссылки, если сможете.
  • если вы решите передать ссылку const, тогда, в зависимости от типа вашего подключения, QT передаст вам значение объекта (см. this для некоторых подробности)
  • избегать любых проблем и передавать по значению:)

См. также question за некоторые мысли о прохождении указателей в сигналах.

Ответ 2

Для вашего первого вопроса используйте QPointer

Для вашего второго вопроса

Если я понял ясно, даже если вы отправляете myObject, у вас все еще есть ссылка myObject в классе, в котором вы излучаете сигнал. Тогда как это будет утечка памяти или свисающий указатель? Вы все еще можете получить доступ к myObject из испущенного класса, не?

Надеюсь, я поняла..

Изменить:

Из ваших комментариев я считаю, что вы выпускаете/удаляете объекты в слотах. Теперь я предполагаю, что ваша проблема в том, что если слот (освобождение памяти) вызывается один раз, дважды или вообще не вызывается.

Для этого вы можете использовать QPointer. Из документации Qt,

Защищенные указатели (QPointer) полезны, когда вам нужно сохранить указатель на QObject, который принадлежит кому-то другому, и поэтому может быть уничтожен, пока вы все еще держите ссылку на него. Вы можете безопасно проверить указатель на достоверность.

Пример из самой документации Qt,

     QPointer<QLabel> label = new QLabel;
     label->setText("&Status:");
     ...
     if (label)
         label->show();

объяснение продолжается так.

Если QLabel будет удалён тем временем, переменная метки будет содержать 0 вместо недопустимого адреса, и последняя строка никогда не будет выполнена. Здесь QLabel будет вашим MyClass, а меткой будет ваш myObject. И прежде чем использовать его, проверьте Nullity.

Ответ 3

В 1): отправитель должен позаботиться. При отправке сигнала синхронно (вместо очереди) объект все еще жив, когда приемник принимает его. Если приемнику необходимо его сохранить, только QPointer поможет, но тогда MyClass должен получить от QObject, который выглядит неправильно из контекста. Во всяком случае, это общая проблема с продолжительностью жизни, а не очень специфическая для сигнала/слота.

Альтернативы: используйте класс значений и отправьте его по ссылке const. Если MyClass может иметь подклассы, передайте const QSharedPointer &

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

Ответ 4

Одним словом (хорошо, имя функции) - deleteLater():) Все объекты QObject имеют его. Он будет отмечать объект для удаления, и это произойдет в следующем обновлении цикла событий.