Jak zwolnić pamięć?

2011-09-23 13:58
michal1879
0

Witam. Jak zwolnić pamięć w przypadku takiego kodu?

#include <iostream>
using namespace std;

class Napoj {
    public:
        virtual double koszt() = 0;
        virtual ~Napoj();
};

class Kawa : public Napoj {
    public:
        double koszt() {
            return 1.20;
        }

        ~Napoj()
        {
            cout << "Usuwam KAWE" << endl;
        }
};

class Mleko : public Napoj {
    public:
        Napoj *napoj;

        Mleko(Napoj *n) { napoj = n; }

        double koszt() {
            return napoj->koszt() + 0.20;
        }

        ~Napoj()
        {
                cout << "Usuwam MLEKO" << endl;         
                delete this->napoj;
        }
};

int main() {
    Napoj *napoj = new Kawa;
    napoj = new Mleko(napoj);
    napoj = new Mleko(napoj);

    cout << napoj->koszt() << endl;

    delete napoj;

    return 0;
}

Z góry dziękuje za pomoc.

Pozostało 580 znaków

2011-09-23 14:10
0

Tsk tsk...lista twych przewinień jest długa...no ale od początku.

-pamięć zaalokowana przez program przeważnie jest zwalniana z automatu przez system po zakończeniu się programu.Niemniej,taki sposób pisania programów to najlepsza droga do wyrobienia sobie nawyków pisania przepięknych memory leaków :] Dlatego patrz niżej:
-wskaźnikowi napoj alokujesz co rusz to nowe obszary pamięci,tracąc zarazem dostęp do poprzednich-a zatem i możliwość ich dealokacji deletem.To jest tak baardzo zue,że aż ciary przechodzą :p
Poprawnie powinieneś stworzyć 2 nowe wskaźniki na te 2 kawy z mlekiem.
-to delete napoj tak jak piszę wyżej załatwi ci dealokację wyłącznie aktualnie wskazywanego prze
napoj obszaru pamięci,tj 2 kawy z mlekiem.Kawa z mlekiem nr 1 i sama Kawa nie zostaną ruszone i dopiero system podczas zakończenia programu powinien zwolnić pamięć przez nie zajmowaną.
-Generalnie twój projekt tych klas taki nie najszczęśliwszy trochę,ot co na przykład w sytuacji kiedy ktoś zażyczy sobie kawy z mlekiem i ajerkoniakiem?
-Widzę wywołanie delete napoj w destruktorze klasy Mleko.Tsk tsk...to jest samoistne proszenie się o klopoty,takie kasowanie wskaźnikow stworzonych na zewnątrz i przekazanych do klasy.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
edytowany 1x, ostatnio: MasterBLB, 2011-09-23 14:17

Pozostało 580 znaków

2011-09-23 14:56
1
MasterBLB napisał(a)

-pamięć zaalokowana przez program przeważnie jest zwalniana z automatu przez system po zakończeniu się programu.

bullshit. takie cos mogl napisac tylko student informatyki, i to mierny student.

MasterBLB napisał(a)

Niemniej,taki sposób pisania programów to najlepsza droga do wyrobienia sobie nawyków pisania przepięknych memory leaków .

proba rehalibitacji ale smrod i tak zostal...


!user image
I am he who watches they. I am the fist of retribution. That which does quell the recalcitrant. Dare you defy the Warchief? Dare you face my merciless judgement?

Pozostało 580 znaków

2011-09-23 20:45
0

Doprawdy?Bo ja widzę potwierdzenie moich wiadomości:
http://forum.warsztat.gd/index.php?topic=9981.0
http://forum.ks-ekspert.pl/to[...]953-cinne-zwalnianie-pamieci/
czyli że (mowa tu o Windows) zaalokowana przez program pamięć jest zwalniana przez system kiedy program się skończy.Przeważnie

No ale,pogrzebię na MSDNie,to pewniejsze źródło.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
edytowany 1x, ostatnio: MasterBLB, 2011-09-23 21:08
Ano, twoje wiadomosci potwierdzili inni lamerzy... - EgonOlsen 2011-09-26 09:53

Pozostało 580 znaków

2011-09-23 20:45
michal1879
0

Poprawnie powinieneś stworzyć 2 nowe wskaźniki na te 2 kawy z mlekiem.

To jest ciągle ta sama kawa tylko udekorowana dodatkami. Próbuje uporać z dekoratorem w C++. W C#/Javie nie ma problemów, bo pamięć zwolni się sama a tutaj potrzebuje w sposób rekurencyjny zwolnić pamięć którą wcześniej zaalokowałem. Ale destruktory się nie wykonują w ten sposób w jaki próbowałem.

Pozostało 580 znaków

2011-09-23 20:50
0

W tym rzecz,że to NIE JEST ta sama kawa-powstają 2 NOWE obiekty klasy Mleko,zaś nie przechowujesz wskaźników do oryginalnej kawy i mleka,zatem nie masz możliwości ich zwolnienia.Ja bym te klasy zrobił innaczej:

Class Napoj
{
   List<Napoj*> dodatki;

public:
   void dodatek(Napoj *n)
   {
      dodatki.append(n);
   }
   virtual double koszt()=0;
   virtual ~Napoj()
   {
       for(int cnt=0;cnt<dodatki.size();cnt++) delete dodatki[cnt];
   }
};

Class Kawa
{
public:
  double koszt(void)
  {
     double cena=ileś_tam;
     for(int cnt=0;cnt<dodatki.size();cnt++)
     {
        cena+=dodatki[cnt]->koszt();
     }
     return cena;
  }
};

a potem w kodzie używasz w łatwy sposób tworząc przenajróżniejsze kombinacje napojów:

Kawa *kawa_z_mlekiem=new Kawa;
kawa_z_mlekiem->dodatek(new Mleko);

itd;

UWAGA od dłuższego czasu piszę przy użyciu kontenerów Qt,zatem jak wygląda użycie standardowej listy to tak dokładnie nie pamiętam.Jakby co,to na stronie C++ reference jest dokładny opis


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
edytowany 3x, ostatnio: MasterBLB, 2011-09-23 21:07

Pozostało 580 znaków

2011-09-23 21:04
michal1879
0

Przy dodawaniu dodatku do napoju przekazuje w konstruktorze wskaźnik do poprzedniego obiektu:

class Mleko : public Napoj {
        public:
                Napoj *napoj; // tu mam wskaźnik do poprzedniego 'napoju'

                Mleko(Napoj *n) { napoj = n; }

                double koszt() {
                        return napoj->koszt() + 0.20;
                }

                ~Napoj()
                 {
                                cout << "Usuwam MLEKO" << endl;                        
                                delete this->napoj;
                }
};

Przy wywołaniu metody koszt() w rekurencyjny sposób obliczam cene za napój i w ten sam sposób chciałbym zwalniać pamięc, ale niestety destruktory się nie wywołują.

dodałem kod przy poprzednim poście,zerknij. - MasterBLB 2011-09-23 21:10

Pozostało 580 znaków

2011-09-24 07:33
0

@MasterBLB: przekombinowałeś ;)

@michal1879: kod jest prawie dobry, poza tym, że nie powinien się skompilować a potem nawet zlinkować. W klasach Mleko i Kawa zmień nazwy destruktorów na poprawne(takie same jak nazwa klasy). W klasie napój musisz napisać definicję destruktora(musi oczywiście zostać jako wirtualny), może być pusty. Kontrolnie wrzuć sobie tam np. cout << "usuwam NAPÓJ" << endl;, zobaczysz wtedy jak te destruktory są wywoływane.


Eee,gdzie tam widzisz przekombinowanie? - MasterBLB 2011-09-24 09:56
przemodelowałeś mu cały kod, który był prawie poprawny. No i jak autor napisał, chciał zaimplementować wzorzec dekorator, a nie najzwyklejszą agregację - byku_guzio 2011-09-24 10:13
Akurat do tego co sobie umyślił autor wzorzec dekorator tak średnio pasuje-ot moje pytanie co będzie jak przyjdzie mu zrobić kawę z mlekiem i koniakiem?No nie ma bata,musi być lista dodatków a nie jeden wskaźnik. - MasterBLB 2011-09-24 10:54
Oj tam, ja to widzę tak, że ten pomysł kawa i mleko to tylko taka idea, żeby mieć powód na zastosowanie tego wzorca. Ot nie wzorzec dla problemu tylko problem dla wzorca co by poćwiczyć - byku_guzio 2011-09-24 11:00
Przeniosłem kontynuację do postu - MasterBLB 2011-09-24 11:30

Pozostało 580 znaków

2011-09-24 11:28
0

Hmm jeśli się uczyć wzorców,to imo należy porządnie.W tym modelu autora pomijając już błędy implementacyje są poważne błędy koncepcyjne:
1)Sprzeczne z intuicją zapytanie o cenę.Żeby otrzymać prawidłowy koszt napoju trzeba się zapytać o cenę mleka.No powiedz byku_guzio czy jak zamawiasz sobie kawę z dodatkiem mleka to jak się pytasz o cenę,"ile za kawę" czy "ile za mleko"?
2)Błąd nieco bardziej technicznej natury-z kodu autora wnioskuję,że chciał on utworzyć kawę z podwójnym mlekiem.Niestety,z uwagi na taką a nie inną implementację nie może się spytać po prostu kawa->koszt() tylko musi poprzez owo z życi wzięte mleko->koszt().I tu jest haczyk,bo nie dość że musi zrobić to 2 razy,to w przypadku sumowania otrzymanych wartości mleko->koszt() (a musi to zrobić) będzie jeszcze musiał uwzględniać iż cena kawy została już wliczona podczas pierwszego wywołania.

Co zaś do nauki wzorca-w nim nie ma niczego takiego co by trzeba intensywnie ćwiczyć,ot dostaje się obiekt do dekoracji i wywołuje jego metody.Generalnie jego istotą jest to,że nie ma powiązania na zasadzie dziedziczenia między dekoratorem a dekorowanym;jeśli zaś są,to jak autor widzi dochodzi to podobnych kwiatków jakie stworzył :P


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
edytowany 1x, ostatnio: MasterBLB, 2011-09-24 11:30
Bo zakładasz, że kupujesz kawę z mlekiem. A to jest po prostu mleko z kawą. - iooi 2011-09-24 16:29

Pozostało 580 znaków

2011-09-24 12:38
michal1879
0

Dziękuje Wam za pomoc:) Teraz już kod działa. Co do przykładu to pochodzi on z książki Head First Design Patterns i jest akurat dostepny w darmowym rozdziale: http://pdf.helion.pl/hfdepa/hfdepa-3.pdf . Nie wiem jak dla innych ale dla mnie, jako początkującego świetnie ilustruje ten wzorzec.

Co zaś do nauki wzorca-w nim nie ma niczego takiego co by trzeba intensywnie ćwiczyć

Hmm, wzorców może nie trzeba ćwiczyć, książke czytałem za pierwszym razem, implementowałem je w Javie i problemów nie było, natomiast próbując je teraz przenieść do C++ mam problemy jak widać z samym językiem :)

Pozdrawiam i dziękuje za odpowiedzi :-)

Pozostało 580 znaków

Liczba odpowiedzi na stronę

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