Здесь, мое объявление сигнала:
signals:
void mySignal(MyClass *);
И как я использую его:
MyClass *myObject=new myClass();
emit mySignal(myObject);
Здесь прибывает моя проблема: Кто ответственен за удаление myObject:
Код отправителя, что, если это удаляет прежде, используется myObject? Висячий указатель
Слот соединился с сигналом, что, если нет никакого слота или больше чем одного слота, который подключен к сигналу? Утечка памяти или Висячий указатель
Как спокойный управляет этой ситуацией в ее сборке - в сигналах? Это использует подсчет внутренней ссылки?
Каковы Ваши лучшие практики?
Вы можете соединить сигнал со сколь угодно большим количеством слотов, поэтому вы должны убедиться, что ни один из этих слотов не может делать то, что вы не хотели бы, чтобы они делали с вашим объектом:
const
ссылку, то, в зависимости от типа вашего соединения, QT передаст значение объекта за вас (см. this для некоторых деталей)Смотрите также question для некоторых мыслей о передаче указателей в сигналах.
В 1): Отправитель должен быть осторожен. При синхронной отправке сигнала (вместо очереди) объект все еще жив, когда его получает получатель. Если получателю нужно сохранить его, то поможет только QPointer, но тогда MyClass должен быть производным от QObject, что в контексте выглядит неправильно. В любом случае, это общий вопрос времени жизни, не очень специфичный для сигнала/слота.
Альтернативы: Использовать класс значений и передавать его через const-ссылку. Если MyClass может иметь подклассы, передавайте const QSharedPointer&
Насчет deleteLater: deleteLater() здесь не поможет. Она сделает соединения в очереди более безопасными, а для прямых соединений она не имеет никакого значения. Единственный случай, когда deleteLater() вступает в игру, это если получателю нужно удалить отправителя. Тогда всегда следует использовать deleteLater(), чтобы отправитель мог завершить то, что он делал, иначе произойдет сбой.
Для первого вопроса используйте QPointer
Для второго вопроса,
Если я правильно понял, даже если вы посылаете myObject
, у вас все еще есть ссылка myObject
в классе, в котором вы посылаете сигнал. Тогда как это будет утечка памяти или висячий указатель? Вы все еще можете получить доступ к myObject
из излучаемого класса, не так ли?
Надеюсь, все ясно...
Edit :
Из ваших комментариев я полагаю, что вы освобождаете/удаляете объекты в слотах. Теперь я предполагаю, что ваша проблема в том, что если (освобождающий память) слот будет вызван один, два раза или не будет вызван вообще.
Для этого вы можете использовать QPointer. Из документации Qt:
Охраняемые указатели (QPointer
) полезны, когда вам нужно хранить указатель на QObject
, который принадлежит кому-то другому, и поэтому может быть уничтожен, пока вы все еще держите ссылку на него. Вы можете безопасно проверить указатель на достоверность.
Пример из самой документации Qt,
QPointer<QLabel> label = new QLabel;
label->setText("&Status:");
...
if (label)
label->show();
объяснение продолжается следующим образом...
Если в это время QLabel будет удален, переменная label будет содержать 0 вместо недопустимого адреса, и последняя строка никогда не будет выполнена. Здесь QLabel будет вашим MyClass
, а label - вашим myObject
. И перед использованием проверьте его на Nullity.
Одним словом (ладно, название функции) - deleteLater() :) Она есть у всех объектов QObjects. Она пометит объект для удаления, и это произойдет при следующем обновлении цикла событий.