delete this;

noisy
  • Rejestracja:ponad 17 lat
  • Ostatnio:prawie 9 lat
0

Witam.

dzisiaj w pewnym kodzie znalazłem ciekawe wyrażenie...

Kopiuj
....
void Foo::Destroy()
{
    delete this;
}
...

Na początku bardzo się zdziwiłem skąd takie wyrażenie. Pogóglałem odrobinę, popytałem trochę i juz wiem, że jest legalne :) Wiem już też (co jest dość logiczne), że po delete this nie można korzystać z żadnych memberów clasy, gdyż ich już najpewniej po prostu nie ma. Także nie powinno się tego wyrażenia używać w destruktorach, gdyz to spowoduje najpewniej nieskończoną pętlę, lub od razu crash...

Pytania mam do was dwa.
Czy znacie jakaś książkę lub artykół, gdzie ten przypadek jest opisywany? Jakie może jeszcze niesć ze sobą skutki używanie takiego wyrażenia..? Na co trzeba wówczas szczególnie uważać

oraz drugi, to co w sumie bardziej mnie interesuję...
Czy sami potraficie wskazać zastosowania takiego wyrażenia. Czyli kiedy np nie można się bez tego obyć?

Pozdrawiam!

DR
"memberów clasy" - co to za język, polski++ ?
rnd
  • Rejestracja:około 17 lat
  • Ostatnio:ponad 13 lat
0

Taka konstrukcja wymusza przydział pamięci dla instancji klasy na stercie. Jak utworzysz klasę na stosie to taki kod pewnie wywali ci program.
Ja bym nie stosował takich trików. Jedyne zastosowanie jakie widzę to wtedy gdybyś w jakiś sensowny sposób przeciążył operator delete.


#define TRUE FALSE
//Happy debugging suckers :D
Riddle
Sygnaturka wymiata.
msm
@TomRiddle - teraz ją zauwazyłeś? :P Btw. ten wątek to teraz archeologia...
Riddle
Nie popatrzyłem na datę.
noisy
  • Rejestracja:ponad 17 lat
  • Ostatnio:prawie 9 lat
0

no faktycznie...to jest jedna z konsekwencji...

Wszakże po wykonaniu delete this z jakiej kolwiek metody, automatyczne wywołanie destruktora (na skutek opuszczenia zakresu ważności) faktycznie spowoduje kasacje nie naszego juz obszaru pamięci...

Ja bym nie stosował takich trików.

na obecnym etapie mojej znajomości tego, to też bym tego nie stosował, bo nie wiem czym to grozi ;)

Znalazłem to jednak w dość poważnym kodzie, stąd stwierdzam, że to jednak ma swoje poważne zastosowanie ;)

rnd
  • Rejestracja:około 17 lat
  • Ostatnio:ponad 13 lat
0

A możesz pokazać ten kod?
Możesz również sprawdzić czy detele nie jest przeciążony.


#define TRUE FALSE
//Happy debugging suckers :D
adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 12 lat
0

Raz użyłem takiej konstrukcji opakowując okno WinAPI w klasę. Klasa okna jest niszczona wraz nadejściem komunikatu WM_DESTROY. Dzięki temu nie musiałem pamiętać wskaźników do klas i ręcznie ich zwalniać.
A oto fragment:

Kopiuj
TapWindow::~TapWindow()
{
   mDeleting = true;
   if(mHandle) DestroyWindow(mHandle);
}

LRESULT TapWindow::WindowProc(UINT Msg, WPARAM wParam, LPARAM lParam)
{
   if((Msg >= WM_MOUSEFIRST) && (Msg <= WM_MOUSELAST))
      OnMouseMessage(Msg, lParam, wParam);
   else switch(Msg)
   {
   case WM_DESTROY:
      if(mDeleting) mHandle = NULL;
      else { delete this; return 0; }
      break;
   }
   return CallWindowProc((FARPROC) mOldWndProc, mHandle, Msg, wParam, lParam);
}

Tyle, że nie można było tworzyć tych klas na stosie. Aby wymódz to ograniczenie na kodzie, można ukryć konstruktor (tj. zrobić go chronionym lub prywatnym) i dostarczyć statyczną metodę tworzącą obiekt na stercie. Zamiast tego ograniczenia można objąć delete w try...except.
Jak widać problem destruktora rozwiązałem zmienną 'mDeleting'.
Więcej zagrożeń nie dostrzegam.

06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
0
rnd napisał(a)

Jedyne zastosowanie jakie widzę to wtedy gdybyś w jakiś sensowny sposób przeciążył operator delete.

A po co to przeciążanie? A co powiesz o klasach z licznikiem referencji np. interfejsy COM z IUnknown?

delete this to dość powszechny "trik".

adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 12 lat
0

Ten "trick" ma ogólnie zastosowanie tam, gdzie istnieje jakaś automatyzacja w zarządzaniu pamięcią wbudowana w same obiekty zarządzane.

quetzalcoatl
  • Rejestracja:ponad 18 lat
  • Ostatnio:ponad 6 lat
0

spotkalem raz w kompilatorze bodajze visual studio 2003 albo 2005 blad, ktory przy pewnej specyficznej konstrukcji klasy oraz kompilacji w trybie debug powodowal ze proba delete this; na poprawnym obiekcie na stercie co prawda sie udawala, ale ... program nie byl w stanie wyjsc z metody w ktorej owo delete this zostalo wykonane. metoda prawidlowo dochodzila do konca, po czym nastepowal crash - program skakal w blizej nie okreslone miejsce pamieci, bynajmniej nie tam gdzie powinien wrocic z metody.. ciekawe czy sobie zachowalem ten kawalek kodu..

//down: kompletnie juz nie pamietam szczegolow, sorry


no to pojechałem z nieobecnością.. chwila przerwy i prawie rok przeleciał
noisy
  • Rejestracja:ponad 17 lat
  • Ostatnio:prawie 9 lat
0

a czy była to metoda virtualna? Albo wywoływana z innej metody virtualnej?

0

Cześć,

Być może moje pytania są dość naiwne, ale...

adf88 napisał(a)

Dzięki temu nie musiałem pamiętać wskaźników do klas i ręcznie ich zwalniać.

Czy chodzi o wskaźniki do klasy TapWindow?
Nie do końca rozumiem sens stosowaniu wspomnianej konstrukcji (tj. delete this). Niezależnie od tego ile masz wskaźników wskazujących na pojedynczy obiekt tej klasy, to jeżeli tenże obiekt został utworzony na stercie, to i tak konieczne i wystarczające jest tylko jednokrotne użycie operatora new. Tutaj możesz zniszczyć okno przekazując funkcji WindowProc WM_DESTROY jako Msg, ale i tak musisz wiedzieć, dla którego konkretnie okna tej klasy masz tą metodę wywołać. Nie dostrzegam tutaj jakichś znacznych korzyści, które miałyby wynikać z tego rozwiązania.
Dlaczego piszesz, że konieczne jest stworzenie statycznej metody tworzącej obiekt na stercie?
Co się stanie jeżeli utworzymy obiekt tej klasy na stosie?
Na czym polega problem destruktora?

43
Jedna sprawa to wywołanie funkcji WinApi odpowiedzialne za zwalnianie "jakichś" danych po stronie systemu ( handle okna, zasoby z nim związane itd. ), a inna sprawa zwolnienie pamięci obiektu wewnątrz twojego progamu. Dlaczego piszesz, że konieczne jest stworzenie statycznej metody tworzącej obiekt na stercie? Nie jest konieczne, ale to jedyne zabezpieczenie inne od "NIE RÓB TEGO" w dokumentacji... Co sięstanie jeżeli utworzymy obiekt tej klasy na stosie? Crash.
43
  • Rejestracja:około 14 lat
  • Ostatnio:ponad 6 lat
  • Postów:61
0

C++FAQ głosi, że delete this; ma więcej minusów niż plusów.

Crash aplikacji przy deklarowaniu w inny sposób niż dynamicznie jest największym.

Jednak , na przykład, wxWidgets stosuje tę konstrukcję nagminnie, podczas kasowania okien.
Powód dość prosty: zapamiętywanie i manualne kasowanie wszystkich wskaźników to "pain in the ass".

Każde okno zapamiętuje wszystkie swoje child windows ( a w przypadku kontrolek może ich być bardzo dużo ) i jest odpowiedzialna za usunięcie każdego z nich, gdy same okno jest usuwane - stąd virtualna metoda odpowiedzialna za skasowanie okna ( wywołanie do WInApi ) i zwolenienie pamięci ( delete this; ).

Ma to swoje korzyści, na pewno.

A zabezpieczenie przed tworzeniem na stosie obiektów dziedziczących z wxWindow jest dość proste = oczojebne "NIE RÓB TEGO" w dokumentacji...

edytowany 2x, ostatnio: 4ggr35510n

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.