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

Вот моя сигнальная декларация:

signals:
    void mySignal(MyClass *);

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

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

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

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

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

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

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


person metdos    schedule 06.07.2010    source источник


Ответы (4)


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

См. также этот вопрос, чтобы узнать о передаче указателей в сигналах.

person Ando    schedule 06.07.2010

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

Что касается вашего второго вопроса,

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

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

Редактировать :

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

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

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

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

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

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

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

person liaK    schedule 06.07.2010
comment
утечка памяти: когда MyClass *myObject выходит за рамки и слот не подключен. висячий указатель: один из слотов удаляет объект, а слотов больше одного. - person metdos; 06.07.2010

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

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

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

person Frank Osterfeld    schedule 06.07.2010

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

person leinir    schedule 06.07.2010