Sygnały/sloty, co siedzi pod spodem.

0

Mam pewną zagwozdkę, którą zamierzam przetestować empirycznie aczkolwiek nie zaszkodzi podyskutować trochę teoretycznie :) Otóż mam takie coś:

void Foo()
{
   std::auto_ptr obj(new FancyObj());
   DoSome(obj);
}

I wszystko byłoby fajnie, ale w funkcji DoSome() przekazywany obiekt może być wysyłany kutekowym sygnałem. Poczułem się w tym momencie niepewnie gdyż tak naprawdę nie wiedziałem jak ten cały mechanizm działa i czy na pewno mogę być pewny że przy wyjściu z funkcji Foo() zaalokowana pamięc zostanie zwolniona.
Z lektury strzępków jakie znalazłem w internecie i kodu wygenerowanego przez MOC wyszło mi, że dopóki odbiorca jest w tym samym wątku to nie powinno się nic dziwnego dziać....chyba.
Jeśli ktoś podzieli się wartościowym materiałem na temat jak działa mechanizm sygnałów slotów pod spodem będę wdzięczny ;)

0

Nie wiem jak dokładnie zaimplementowane są sygnały i sloty w qt, więc napiszę tylko jak ja bym to rozwiązał.
Przede wszystkim zrezygnowałbym z std::auto_ptr, bo jest on deprecated.
W tym przypadku użyłbym std/boost::shared_ptr a do metody przesyłałbym std/boost::weak_ptr (lock() z std/boost::weak_ptr jest thread safety).
Ewentualnie można by użyć std::unique_ptr/boost::locked_ptr i przez std::move przekazać go do metody DoSome().

2

Ja bym nie mieszał boost/stl z Qt tam, gdzie jest to niepotrzebne (a w nowym kodzie w zasadzie zawsze jest to niepotrzebne).

Polecam poczytać opis enuma (Qt::ConnectionType) użytego jako piąty parametr dla connect (piąty parametr ma wartość domyślną, więc zwykle się to przegapia).
Czyli jeśli przekazywanie sygnału jest pomiędzy jednym wątkiem (z domyślnym typem połączenia) lub użyte zostało Qt::DirectConnection to ryzyka nie ma (sygnał-slot zachowuje się jak zwykłe wywołanie funkcji).

Jeśli jednak połączenie sygnał slot powoduje kolejkowanie wywołania slotu w event loop, to odebranie sygnału może nastąpić już po śmierci problematycznego obiektu i na to trzeba uważać.
Jeśli twój umierający obiekt był emiterem wtedy wartość sender() będzie miała wartość null i dobry kod powinien to bez problemu obsłużyć.
Jeśli przekazujesz, go przez parametr to trzeba użyć smart pointera (auto_ptr zawiedzie tu na całej linii on się po prostu nie nadaje do sygnałów i slotów z powodu swojej największej wady). Można użyć wskaźnika QSharedPointer, który podtrzymuje, życie obiektu dopóki choć jeden pointer tego typu wskazuje na ten obiekt.

A jeszcze jedno warto zrozumieć dziwne zachowanie deleteLater. deleteLater zachowuje się nietypowo w event loopie, normalnie nie ma znaczenia, który event loop przetwarza zdarzenie (event loop'y mogą być zagnieżdżone), w przypadku przetwarzania deleteLater jest takie rozróżnienie (qt stara się zawsze wykonać usuniecie w event loopie zewnętrznym względem wywołania deleteLater), radzę przeczytać uważnie dokumentację.

1 użytkowników online, w tym zalogowanych: 0, gości: 1