• 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

Object Storage Arubacloud
+1 głos
218 wizyt
pytanie zadane 26 listopada 2021 w C i C++ przez Maciek123233 Gaduła (3,400 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,400 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ź 207 wizyt
0 głosów
3 odpowiedzi 456 wizyt
pytanie zadane 5 października 2017 w C i C++ przez hitem Początkujący (300 p.)
0 głosów
1 odpowiedź 339 wizyt

92,552 zapytań

141,399 odpowiedzi

319,534 komentarzy

61,938 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...