2010-07-06 13 views
16

Tutaj moja deklaracja sygnał:Usuwanie obiektów wysyła sygnały, własności obiektów w sygnały, Qt

signals: 
    void mySignal(MyClass *); 

A jak używam go:

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

Nadchodzi mój problem: Kto jest odpowiedzialny za usunięcie myObject:

  1. Kod nadawcy, co jeśli zostanie usunięty przed użyciem myObject? Zwisający wskaźnik

  2. Gniazdo podłączone do sygnału, co jeśli nie ma gniazda lub więcej niż jednego gniazda, które jest podłączone do sygnału? Wyciek pamięci lub zwisający wskaźnik

W jaki sposób Qt radzi sobie z tą sytuacją w sygnałach wbudowanych? Czy używa wewnętrznego liczenia odwołań?

Jakie są Twoje najlepsze praktyki?

Odpowiedz

9

można podłączyć sygnał z tak wieloma szczelinami jak chcesz więc należy upewnić się, że żaden z tych gniazd są w stanie zrobić coś, czego nie chcesz, żeby zrobić z obiektem:

  • jeśli zdecyduj się przekazać wskaźnik jako parametr, a następnie będziesz pracował w opisywanych problemach, zarządzaniu pamięcią - nikt nie może za ciebie pracować, ponieważ będziesz musiał ustanowić politykę dotyczącą alokacji/usuwania. Kilka pomysłów na rozwiązanie tego problemu znajduje się w Regułach zarządzania pamięcią w świecie COM.
  • Jeśli zdecydujesz się przekazać parametr jako odniesienie, nie musisz się martwić o zarządzanie pamięcią, ale tylko o sloty modyfikujące obiekt w nieoczekiwany sposób. Ideea nie przekazuje wskaźników, chyba że musisz - zamiast tego użyj referencji, jeśli możesz.
  • jeśli zdecydujesz się przekazać const odniesienie następnie, w zależności od typu połączenia, QT minie wartość przedmiotu dla Ciebie (patrz this dla niektórych szczegółów)
  • uniknąć problemów i przejść przez wartość :)

Zobacz także ten question dla niektórych myśli o przekazywaniu wskaźników sygnałów.

0

Jednym słowem (w porządku, nazwa funkcji) - deleteLater() :) Wszystkie obiekty QObject mają to. Zaznacza obiekt do usunięcia, a stanie się to podczas kolejnej aktualizacji pętli zdarzeń.

5

Na swoim pierwszym pytaniu, należy QPointer

Na drugie pytanie,

Gdybym zrozumiał jasno, nawet jeśli wysyłasz myObject, ty jeszcze odniesieniemyObject w klasie, gdzie jesteś emitowanie sygnału. Jak to będzie wyciek pamięci lub zwisający wskaźnik? Nadal możesz uzyskać dostęp do z myObject z emitowanej klasy, prawda?

Nadzieja am jasne ..

Edit:

Od komentarze Wierzę, że wypuszczamy/usuwanie obiektów w szczelinach. Teraz zakładam, że twój problem polega na tym, że jeśli slot (zwalnianie pamięci) zostanie wywołany raz, dwa razy lub w ogóle nie zostanie wywołany.

Możesz użyć QPointer do tego. Z dokumentacji Qt,

strzeżony wskaźniki (QPointer) są użyteczne, gdy trzeba przechowywać wskaźnik do QObject który jest własnością kogoś innego, a zatem może zostać zniszczony podczas nadal posiadają odniesienie do niego. Możesz bezpiecznie przetestować wskaźnik pod kątem poprawności.

Przykład z dokumentacją samego Qt,

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

wyjaśnienie idzie tak ..

Jeśli QLabel zostanie usunięty w międzyczasie, zmienna etykieta odbędzie 0 zamiast nieprawidłowy adres, a ostatnia linia nigdy nie zostanie wykonana. Tutaj QLabel będzie twoim MyClass, a etykieta to Twoja myObject.Przed użyciem sprawdź, czy nie ma ono wartości Nullity.

+0

wyciek pamięci: gdy MyClass * myObject wykracza poza zakres i gniazdo nie jest podłączone. zwisający wskaźnik: jeden z gniazd usuwa obiekt, a jest więcej niż jedno gniazdo. – metdos

+0

QPointer jest teraz moim wyborem! dzięki! – Brent81

3

Na 1): Nadawca powinien zachować ostrożność. Podczas wysyłania sygnału synchronicznie (zamiast w kolejce), obiekt jest wciąż żywy, gdy odbiornik go odbierze. Jeśli odbiornik musi go przechować, pomógłby mu tylko QPointer, ale wtedy MyClass musi czerpać z QObject, który wygląda nieprawidłowo z kontekstu. W każdym razie jest to ogólny problem dotyczący całego życia, niezbyt specyficzny dla sygnału/slotu.

Alternatywy: Użyj klasy wartości i prześlij ją przez odwołanie do stałej. Jeśli MyClass może mieć podklasy, należy przekazać const QSharedPointer &

Informacje o deleteLater: deleteLater() tutaj nie pomaga. Dzięki temu kolejkowanie połączeń będzie bezpieczniejsze, a dla połączeń bezpośrednich nie ma znaczenia. Jednym z zastosowań, w którym wchodzi funkcja deleteLater(), jest to, że odbiorca musi usunąć nadawcę. Następnie należy zawsze używać metody deleteLater(), aby nadawca mógł wykonać to, co robił, co w innym przypadku spowodowałoby awarię.