Zwalnianie obiektów

0

Ostatnio czytam sobie o tworzeniu dynamicznej allokacji pamięci i natknąłem się na bardzo ciekawy wątek.

int *wsk = new int(5); //tworzymy sobie obiekt o wartości 5
int *wsk2 = new int(10); //tym razem o wartości 10

//pracujemy sobie na obiektach...


//... i je zwalniamy, lecz wcześniej wykonaliśmy taką instrukcje
wsk2 = wsk; //odtąd wskaźnik wsk2 pokazuje na to na co wsk

delete wsk;//Zwalniamy obiekt wsk i tym samym zwalniamy jakąś część pamięci
 
//Tutaj nadal pracujemy tworząc nowe obiekty(nie koniecznie dynamiczne). Jeden obiekt zapisany jest w //tym miejscu, co dawniej wsk.

delete wsk2;//HORROR! - zwalniamy powtórnie ten sam adres! Omyłkowo zostaje zniszczony                               //przypadkowy obiekt

Pewnie dla niektórych jest to oczywiste, ale jak to ma się do WINAPI? Otóż odniosłem tworzenie dynamiczny obiektów, do tworzenia i zwalniania obiektów w WINDOWS.

HDC hdcKontekst = GetDC(hWindow);

//tworzymy sobie jakieś tam pióro...
HPEN pioro = CreatePen(PS_SOLID, 3, RGB(0,200,0));

//... i wiążemy z kontekstem, automatycznie usuwając stare pióro.
DeleteObject( SelectObject(hdcKontekst, pioro) );

ReleaseDC(hWindow, hdcKontekst);

DeleteObject(pioro);//BŁĄD??? 

Jak wiadomo, obiekty powiązane z kontekstem giną w chwili jego opuszczenia(w tym przypadku obiekt pioro), a ja dalej ponownie go usuwam. Lubię stosować takie zapisy ponieważ kod jest w tedy przejrzystszy i według tutorialu, który czytam jest to poprawne. Sumienie jednak nie daje mi spokoju, dlatego pytam o wasze zdanie.

P.S Zwykle jeszcze zapisuje sobie stan kontekstu, a potem go przywołuje, w razie gdybym o czymś zapomniał, a na koniec usuwam(DeleteObject) wszystkie utworzone przez siebie objekty.

0

IMHO, skoro niszczenie kontekstu niszczy pioro, nie powinienes pozniej recznie go niszczyc. Jezeli owo DeleteObject(pioro);//BŁĄD??? nie wywala Ci sie zadnym AccessViolation, to znaczy ze uchwyty sa jakos inteligentnie sledzone (watpie) albo miales mega farta (bardziej prawdopodobne)

disclaimer: ale specem od winapi nie jestem

0

Kompilator nie pokazuje błędu, bo jest on... nie wiem jak to nazwać - ukryty. Tak samo jest w przypadku przykładu o wskaźnikach - Kompilator błędu nie pokaże. Ale czyż kod nie wygląda lepiej, gdy usuwa się obiekty jawnie? W takim razie najlepszym rozwiązaniem jest zapisywanie stanu kontekstu, a później przywracanie. Potem można z czystym sumieniem usuwać po kolei obiekty. Wy jak sobie z tym radzicie?

0

Tak samo jest w przypadku przykładu o wskaźnikach - Kompilator błędu nie pokaże.

Ale program pokaże , ,,,

0

No nie do konca niszczysz kontekst a tylko go zwalniasz (roznica pomiedzy CreateDC i DeleteDC a GetDC i RealeaseDC). Swoja droga wystarczy sprawdzic co zwroci funkcja DeleteObject.

i tak jesli wywolasz

DeleteObject(pioro);
DeleteObject(pioro);

to za pierwszym razem bedzie to true a za drugim false (bo juz obiekt bedzie zniszcony)

nie wiem gdzie przeczytales opinie

TOM# napisał(a)

Jak wiadomo, obiekty powiązane z kontekstem giną w chwili jego opuszczenia

(juz ten przyklad wskazuje, ze to nie prawda. DeleteObject zwraca true a zatem obiekt istnial!)

i jesli juz sie programuje w winapi to raczej w taki sposob

HDC hdcKontekst = GetDC(hWindow);

//tworzymy sobie jakieś tam pióro...
HPEN pioro = CreatePen(PS_SOLID, 3, RGB(0,200,0));

//... i wiążemy z kontekstem
HPEN oldpen = SelectObject(hdcKontekst, pioro) ;

DeleteObject(SelectObject(hdcKontekst, oldpen) );//niszczymy pioro
ReleaseDC(hWindow, hdcKontekst);

Dlaczego tak? A mianowicie kontekst musi miec jakies domyslne pioro, zazwyczaj przydzielone przez system (GetStockObject - tu dla ciekawosci mozesz porownac jaki jest uchwyt piora kontekstu i uchwyt zwracany przez GetStockObject(BLACK_PEN)). Nie powinnismy go niszczyc a jedynie wychodzac pozostawic kontekst w takim stanie w jakim go zastalismy, a zniszczyc tylko obiekty, ktore my tworzymy.

Nie probowal bym tu znalezc analogi do wskaznikow.

Swoja droga jaki kurs winapi znalazles ?

PS. Ja obecnie nie widze jakiegos super kursu WinAPI bo juz przestaje byc w modzie (niezle trzeba naklepac w klawiature aby cos zobaczyc). Polecam przyklady do starych IDE borlanda np Borland Pascal 7.0 dla Win 3.11 i chyba tez byla werscj Borland C++ dla 3.11. Generalnie duzo sie nie zmienilo i po lekkim podrasowaniu (a moze i nawet bez) powinny sie kompilowac. Ale nawet juz w tych przykladach dominuje OWL :). Potem MSDN.

PS. A i jescze jedno. Program moze pokazac to jako wyciek pamieci(gdy nie zwolnimy), raczej wielokrotne zwalnianie nie wywola bledu. Nawet jesli pozniej zaznaczymy jakis pusty(zwolniony) obiekt do dostaniemy blad podczas rysowania (funkcja zwroci false i nic nie narysuje albo narysuje starym obiektem).

PS. Stawiam browar kto wyrzuci AV funkcja DeleteObject.

PS.

TOM# napisał(a)

Zwykle jeszcze zapisuje sobie stan kontekstu,
Jak to robisz?

PS. TOM#, bardzo bardzo prosze podaj mi zrodlo, z ktorego czerpiesz te herezje (nie pierwsza). Trzeba je zniszczyc.

0

Link do tego tutorialu:
<url>
http://www.gamedev.pl/tutorials.php
</url>

Stan kontekstu zapisuje się przez wywołanie funkcji SaveDC(HDC Konteskt); i przywołuje z powrotem
funkcją RestoreDC(HDC Kontekst, który stan);. Po takim zastosowaniu między tymi instrukcjami można ignorować wartość zwracaną przez SelectObject();

Przykład:

HDC hdcKontekst = GetDC(hWindow);

//zapisujemy stan
SaveDC(hdcKontekst);

//mamy kilka pędzli, piór, bitmap, oszczędzam sobie ich definicji
//Robimy sobie kilka instrukcji zmieniające standardowe elementy np:
SelectObject(hdcKonteskt, jakies_piuro); //ignorujemy stare

RestoreDC(hdcKontekst, -1);//wczytujemy stan
//W tym momencie kontekst wrócił do pierwotnego stanu

//Spokojnie możemy opuścić kontekst, nie martwiąc się o jakieś wycieki w postaci np. starego pedzla
ReleaseDC(hWindow,   hdcKontekst);


//Tu możemy po kolei usunąć obiekty, których nie będziemy używać.

Co do tutorialu, to ja mogłem coś źle zrozumieć. Ale z tego co wiem, powyższy zapis jest OK.

0

Tak, mozna ignorowac (chcialem wiedziec jaka metode wybrales). Obiekt jednak nalezy zniszczyc. Jednak to nie odnosi sie do tego co pisales wczesniej (tu zakladamy, ze powracasz do kontekstu jaki otrzymales na poczatku, poprzednio kasowales obiekt z GetStockObject - pisze w tym tutorialu, ze nie trzeba).

Jak przeczytasz dokladnie ten kurs (ktory jest dobry, czytaj dokladnie) to jest tam napisane, ze obiekty tworzone przez siebie nalezy zawsze zwalniac. Tylko obiekty z serii GetStockObject tego nie wymagaja.

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