[solved] aplikacja Qt GUI - "upływ" danych?



  • Cześć.
    Mam do napisania aplikację okienkową, która kataloguje zdjęcia według różnych parametrów exif. Polega to na tym, że użytkownik podaje lokalizację folderu ze zdjęciami, program odczytuje wybrane dane, tworzy z nich listę plików i wyświetla. Istnieje możliwość sortowania po każdym parametrze, rosnąco lub malejąco. Program uruchamia się, wyświetla listę plików poprawnie, pierwsze sortowanie też działa, dalej ilość pozycji się zmniejsza, aż w końcu program przestaje działać. Czasem działaja jedno sortowanie, czasem kilka. Efekt końcowy jest zawsze taki sam. Upływ danych i zawieszenie się aplikacji - czasem od razu się zawiesza. Co robię źlę?

    Link do plików z programem:
    "program exiv":https://docs.google.com/file/d/0B9NtEembQQvWOHJVcXhEZFlEeGM/edit?usp=sharing

    Dziękuję za pomoc :)


  • Moderators

    Użyj valgrinda, lub nawet zwykłego debuggera żeby zobaczyć gdzie tracisz pamięć. Prawdopodobnie gdzieś coś mieszasz we wskaźnikach.



  • Debuger pokazuje, że coś jest nie tak w pliku sortowanie.cpp, 92 linijka: poprzedni->next = NULL;
    Przeanalizowałem działanie całego programu i nie mam pojęcia dlaczego tam jest źle. Macie może jakieś pomysły?


  • Moderators

    Zdefiniuj "coś jest nie tak". Ustawianie wskaźnika na NULL na pewno nie jest złe samo w sobie, ale z reguły wcześniej dobrze jest zniszczyć ten obiekt (delete). To jednak bardzo zależy od implementacji (czasem dany wskaźnik jest tylko lokalny i nie ma potrzeby niszczyć obiektu, albo jest to QObjekt i niszczeniem zajmie się meta object system).



  • Ale skoro zniszczę obiekt to później nie będę mógł się już odwołać do tego miejsca w liście i program praktycznie w ogóle nie działa. No, chyba, że coś mylę...

    Gdy przestaje działać pojawia się komunikat: Otrzymano sygnał. Podproces zatrzymany, ponieważ otrzymał on sygnał z systemu operacyjnego. Nazwa sygnału: SIGSEGV. Znaczenie sygnału: Segmentation fault.

    Kompilator przenosi mnie do modułu sortowanie.cpp i wskazuje żółtą strzałką na linijkę 92, czyli: poprzedni->next = NULL;

    Jeśli zmienię wątek, to wskazuje na coś takiego: 0x77a700fd <+0x02d3> sub $0x14,%esp

    Jeśli przełączę w tryb debugowania na instrukcjach:
    @
    92 poprzedni->next = NULL;
    0x4035f4 <+0x011f> mov -0x1c(% ebp),% eax
    0x4035f7 <+0x0122> movl $0x0,0x38(% eax)@

    (Błąd w pogrubionej linijce, też wskazywany przez żółtą strzałkę.)

    Wcześniej napisałem aplikację konsolową i wszystko było ok, teraz po podlączeniu nie działa.

    bq. niszczeniem zajmie się meta object system

    Chodzi o destruktor?



  • Nie wiem dlaczego, ale ucina mi część wiadomości.

    Teraz działa, wystarczyło dodać pause po %. Proszę o skasowanie tego postu :)


  • Moderators

    Ok czyli jesteś w sytuacji gdzie nie trzeba nic niszyczyć ;) Nie zaglądam do twojego kodu, także w gruncie rzeczy zgaduję co się dzieje.

    Jeśli tylko poprzedni->next nie jest prywatny (a nie jest, bo by cię kompilator zakrzyczał), to NULL zawsze ustawić możesz. Sprawdź czy gdzieś potem w kodzie nie próbujesz odczytać tego wskaźnika: system wykrzaczy się SIGSEGV właśnie wtedy, gdy próbujesz dostać się do zmiennej wskazywanej przez pointer, a tam nic nie ma (NULL).

    Czyli jeśli dobrze rozumiem, to w debugowaniu program się krzaczy, ale w release działa, tylko ubywa pozycji na liście? Może ubywa dlatego że kasujesz obiekty "next" właśnie?



  • W trybie release (to ten zwykły przysisk play, ctrl+R, zgadza się?) program też w pewnym momencie przestaje działac i wtedy wywala "Program exif_okienkowo.exe przestał działać".

    To moja funkcja sortująca:

    @lista * sortuj_rosnaco(lista * akt_lst, int pole){
    lista * max, *poczatek, *tmp_poczatek, *poprzedni;
    int ten_sam;
    max = akt_lst;
    poczatek = akt_lst;
    tmp_poczatek = akt_lst;

    while(tmp_poczatek->next!=NULL){
        max = tmp_poczatek;
        akt_lst = tmp_poczatek;
        ten_sam = 1;
        while (akt_lst!=NULL){
            if (porownaj_elementy(max, akt_lst, pole)==1){
                max = akt_lst;
                ten_sam--;
            }
            akt_lst = akt_lst->next;
        }
        if (ten_sam == 1){
            if(tmp_poczatek != poczatek){
                tmp_poczatek = tmp_poczatek->next;
                poprzedni = wyszukaj_poprzedni(poczatek, max); //wyciagnac mina
                poprzedni->next = max->next; // zalatac dziure
                max->next = poczatek; // wstawienie na poczatek
                poczatek = max; // zapisanie nowego poczatku
            }else{
                tmp_poczatek = tmp_poczatek->next;
            }
        }else{
            poprzedni = wyszukaj_poprzedni(poczatek, max); //wyciagnac mina
            poprzedni->next = max->next; // zalatac dziure
            max->next = poczatek; // wstawienie na poczatek
            poczatek = max; // zapisanie nowego poczatku
        }
    }
    // trick dla wstawienia ostatniego na poczatek
    poprzedni = wyszukaj_poprzedni(poczatek,tmp_poczatek);
    poprzedni->next = NULL;
    tmp_poczatek->next = poczatek;
    poczatek = tmp_poczatek;
    
    return poczatek;
    

    }@
    Błąd w lini 38. Z każdym kolejnym wywołaniem ubawa pozycji w liście aż w końcu (podejrzewam) program odwołuje się do pola, które "nie istnieje".


  • Moderators

    Zamień linie 37 i 38 albo całkiem skasuj linię 38.



  • Zamiana lini nic nie daje.
    Jeśli skasuję linię 38 to już przy próbie pierwszego sortowanie program się wiesza.
    Dzięki za pomoc :)



  • Zwracanie wskaźników przez funkcję to śliska rzecz, naprawdę ;]

    funkcja wyszukaj_poprzedni może zwrócić NULL a Ty sobie beztrosko linijkę dalej wywołujesz:

    @poprzedni->next = max->next;@

    albo

    @poprzedni->next = NULL;@

    Wypadaloby w każdym przypadku sprawdzić czy przypadkiem wskaźnik nie jest nullem, a ryzyko crasha się zminimalizuje.



  • Dlaczego zwracanie wskaźników przez funckję to śliska rzecz? Jak robić to inaczej?

    Poprawiłem, teraz wygląda to tak:

    @Lista * sortuj_rosnaco(Lista * akt_lst, int pole){
    Lista * max, *poczatek, *tmp_poczatek, *poprzedni;
    int ten_sam;
    max = akt_lst;
    poczatek = akt_lst;
    tmp_poczatek = akt_lst;

    while(tmp_poczatek->next!=NULL){
        max = tmp_poczatek;
        akt_lst = tmp_poczatek;
        ten_sam = 1;
        while (akt_lst!=NULL){
            if (porownaj_elementy(max, akt_lst, pole)==1){
                max = akt_lst;
                ten_sam--;
            }
            akt_lst = akt_lst->next;
        }
        if (ten_sam == 1){
            if(tmp_poczatek != poczatek){
                tmp_poczatek = tmp_poczatek->next;
                poprzedni = wyszukaj_poprzedni(poczatek, max); //wyciagnac max
                if (poprzedni!=NULL){ // tutaj zmiana nr 1
                    poprzedni->next = max->next; // zalatac dziure
                    max->next = poczatek; // wstawienie na poczatek
                    poczatek = max; // zapisanie nowego poczatku
                }
            }else{
                tmp_poczatek = tmp_poczatek->next;
            }
        }else{
            poprzedni = wyszukaj_poprzedni(poczatek, max); //wyciagnac max
            if (poprzedni!=NULL){ // tutaj zmiana nr 2
                poprzedni->next = max->next; // zalatac dziure
                max->next = poczatek; // wstawienie na poczatek
                poczatek = max; // zapisanie nowego poczatku
            }
        }
    }
    // trick dla wstawienia ostatniego na poczatek
    poprzedni = wyszukaj_poprzedni(poczatek,tmp_poczatek);
    if (poprzedni!=NULL) {// tutaj zmiana nr 1
        poprzedni->next = NULL;
        tmp_poczatek->next = poczatek;
        poczatek = tmp_poczatek;
    }
    
    return poczatek;
    

    }@
    Niestety program dalej nie działa poprawnie...



  • bq. Dlaczego zwracanie wskaźników przez funckję to śliska rzecz? Jak robić to inaczej?

    Właśnie dlatego że wszędzie trzeba później sprawdzać poprawność wskaźnika, inaczej to można zwracać referencję do obiektu.

    Odapliłem Twój program i jest crash hell, cokolwiek nie kliknę to wywala się apka ;]

    Chociażby w tym miejcu:
    @ if (el1->nazwa >= el2->nazwa) @

    Dobrze by było jakbyś zapoznał się ze standardowymi kontenerami np. "QList":http://qt-project.org/doc/qt-4.8/qlist.html, bo Twoja implementacja listy to po pierwsze odkrywanie koła na nowo, a po drugie to zamota ze wskaźnikami powoduje totalny brak stabilności.



  • bq. Odapliłem Twój program i jest crash hell, cokolwiek nie kliknę to wywala się apka ;]

    Jeśli nie poda się prawidłowej ścieżki do zdjęć to program się wywala od razu. A dane poprawnie odczytywać będzie chyba tylko z 40D.

    bq. Dobrze by było jakbyś zapoznał się ze standardowymi kontenerami np. QList [qt-project.org], bo Twoja implementacja listy to po pierwsze odkrywanie koła na nowo, a po drugie to zamota ze wskaźnikami powoduje totalny brak stabilności.

    Chyba wchodzimy na zbyt wysoki poziom. :) Nie ma już czasu na przebudowanie całego projektu, może uda się znaleźć jeszcze błąd. W aplikacji konsolowej wszystko działało.



  • Udało mi się naprawić program. Błąd był zupełnie gdzie indziej, wystarczyło dopisać jedną linijkę.

    Mam jeszcze pytanie. Czy da się zrobić i czy dużo jest roboty z tym, aby użytkownik wybierał lokalizację z wykorzystaniem czegoś w rodzaju menadżera windowsa? Tak jak podaję się lokalizację do zainstalowania w programach.

    Dzięki za pomoc :)



  • Czy chodzi Ci o wybieranie ścieżki (folderu) lub pliku? Jeśli tak, to "QFileDialog":http://qt-project.org/doc/qt-5.0/qtwidgets/qfiledialog.html.



  • O coś takiego mi chodziło. Jak znajdę chwilę czasu to postaram się dołożyć. Dziękuję serdecznie!



  • Powodzenia. Pamiętaj, aby w temacie dopisać w nazwie "[solved]" na znak rozwiązania problemu - rozumiem, że upływu danych już nie ma. :-)



  • Nie, nie ma. Miałem błąd w module mainwindow. Wywołując funkcję sortującą przekazywałem zawsze ten sam wskaźnik, tak więc stopniowo ginęły dane, które były wcześniej na liście dynamicznej. Dopisanie linijki załatwiło sprawę. Później usunąłem tą i kilka innych linijek, zmieniłem nazwę wskaźnika na inny (prawdłowy) i śmiga aż miło. Dziękuję raz jeszcze. :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.