• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

[C++] Problem ze zwolnieniem obiektu alokowanego dynamicznie

+1 głos
60 wizyt
pytanie zadane 26 listopada 2021 w C i C++ przez Maciek123233 Gaduła (3,410 p.)

Cześć, napisałem program w którym stworzyłem listę jednokierunkową. Obiekty struct K1 to elementy listy, natomiast struct K2 to główny pojemnik listy. Przy kasowaniu listy (K2 baza;) wywołuje się destruktor który zwalnia kolejne elementy listy zwalnianiu dynamicznych (k1_1, k1_2, k1_3) jednak w momencie gdy usuwam ostatni element do program się wysypuje (gdy dodaje czwarty element, to trzeci już jest normalnie kasowany, a wysypuje się przy czwartym).

Nie rozumiem dlaczego występuje naruszenie ochrony pamięci, szczególnie, że wszystkie poprzednie elementy listy są zwalniane w ten sam sposób.

Żeby zadać to pytanie maksymalnie uprościłem oryginalny kod. Specjalnie usunąłem metody dostępowe i wszystkie zmienne obiektów są publiczne. Zdaję sobie sprawę że tak się nie robi.

#include <iostream>
using namespace std;

struct K1
{
  K1* _next;
  char _c;
  K1(char c)
  {
    cout<<"utworzono ob. "<<this<<endl;
    _c = c;
    _next = 0;
  }
  void wypisz_dane_obiektu()
  {
    cout<<"this:"<<this<<" _c:"<<_c<<" _next:"<<_next<<endl;
  }
  ~K1()
  {
    cout<<"skaskowano ob. "<<this<<endl;
  }
};

struct K2
{
  unsigned int ile_K1;
  K1* pierwszy;
  K1* ostatni;
  ~K2()
  {
    cout<<"kasowanie K2"<<endl;
    K1* ob_poprzedni = pierwszy;
    K1* obiekt_nastepny = pierwszy->_next;
    while(true)
    {
      if(ob_poprzedni == 0)
        return;
      delete ob_poprzedni;
      ob_poprzedni = obiekt_nastepny;
      obiekt_nastepny = obiekt_nastepny->_next;
    }
  }
};

int main()
{
  {
    K2 baza;
    K1* k1_1 = new K1('A');
    K1* k1_2 = new K1('B');
    K1* k1_3 = new K1('C');

    k1_1->_next = k1_2;
    k1_2->_next = k1_3;

    k1_1->wypisz_dane_obiektu();
    k1_2->wypisz_dane_obiektu();
    k1_3->wypisz_dane_obiektu();

    baza.ile_K1 = 3;
    baza.pierwszy = k1_1;
    baza.ostatni = k1_2;

    //automatyczne wywolanie destruktora dla K2 baza;
  }
  cout<<"Tutaj obiekt 'baza' juz nie istnieje ale to juz sie nie wyswietli";
  return 0;
}

 

1 odpowiedź

0 głosów
odpowiedź 26 listopada 2021 przez Sadako Obywatel (1,240 p.)
wybrane 26 listopada 2021 przez Maciek123233
 
Najlepsza
Wystarczy rozpisać sobie jak wygląda przebieg pętli:

Zanim wejdziemy do pętli mamy:

baza.pierwszy = k1_1;
K1* ob_poprzedni = pierwszy;     //         ob_poprzedni == k1_1
K1* obiekt_nastepny = pierwszy->_next;         //   obiekt_nastepny == k1_2

Iteracja 1
ob_poprzedni (k1_1) jest różne od 0 więc nie wychodzimy
usuwamy ob_poprzedni (k1_1)
nowe przypisanie robimy
ob_poprzedni = obiekt_następny (k1_2)
obiekt_następny = obiekt_następny(k1_2)->next (k1_3)

Iteracja 2
ob_poprzedni (k1_2) jest różne od 0 więc nie wychodzimy
usuwamy ob_poprzedni (k1_2)
nowe przyisanie robimy
ob_poprzedni = obiekt_nastepny (k1_3)
obiekt_nastepny = obiekt_nastepny(k1_3)->next(0)

Iteracja 3
ob_poprzedni (k1_3) jest różne od 0 więc nie wychodzimy
usuwamy ob_poprzedni (k1_3)
nowe przypisanie robimy
ob_poprzedni = obiekt_nastepny(0)
obiekt_następty = obiekt_następny(0)->next(????)

Wystarczy ładnie rospisać sobie :) i widać od razu, że gdy usuniesz trzeci element, to następny jest 0 (null), a Ty na tym null robisz jeszcze next. Czegoś takiego nie możesz zrobić.
Musisz tutaj troche pokombinować inaczej, bo tak logicznie nawet biorąc, skoro masz pointer, i pointer na next, to jakie mają być tam wartości po skończonym algorytmie. Sprwadzasz czy ob_poprzedni jest null, jak nie to odwołujesz się do dwóch następnych elementów.
komentarz 26 listopada 2021 przez Sadako Obywatel (1,240 p.)
Dodam jeszcze, że możesz się zastanowić jak ma wyglądać pusta lista, (czyli pierwszy jest 0).
Twój algorytm od razu się wysypiue.jeszcze przed tą pętlą w destruktorze
komentarz 26 listopada 2021 przez Maciek123233 Gaduła (3,410 p.)
Dzięki za odpowiedź, aż mi głupio że nie zauważyłem tak głupiej rzeczy xd

Jeśli chodzi o pustą listę to w oryginalnym kodzie stworzyłem odpowiednie mechanizmy sprawdzające czy ile_ob == 0, tylko nie chciałem tutaj wklejać kilkuset linii kodu i uprościłem całość do tego co tutaj widać.

Podobne pytania

0 głosów
1 odpowiedź 162 wizyt
0 głosów
3 odpowiedzi 244 wizyt
pytanie zadane 5 października 2017 w C i C++ przez hitem Początkujący (300 p.)
0 głosów
1 odpowiedź 232 wizyt

86,482 zapytań

135,238 odpowiedzi

300,475 komentarzy

57,229 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...