Sprawdzenie czy referencja wskazuje na istniejący obiekt

0

Cześć,

mam taki kod:

type
    TObject1 = class
    ... // jakieś pola / metody
    end;

    TObject2 = class
        FObject1: TObject1;
    end;

    TObject3 = class
        FObject1: TObject1;
    end;

var // zmienne globalne
    Object1: TObject1;
    Object2: TObject2;
    Object3: TObject3;

procedure Init;
begin
    Object1 := TObject1.Create;

    Object2 := TObject2.Create;
    Object2.FObject1 := Object1;

    Object3 := TObject3.Create;
    Object3.FObject1 := Object1;
end;

Obiekty 2 i 3 w swoich metodach korzystają z obiektu 1, ale mogą go też zniszczyć. Czy jest jakiś sposób na sprawdzenie czy obiekt do którego mam referencje nadal istnieje?

0

Którą masz wersję Delphi?
Od którejś tam wprowadzili smart pointers - poczytaj o tym.

Edit: oczywiście masz błąd projektowy, skoro mogą go zwolnić, ale tak w sumie to zależy od fazy księżyca. Opisz co tam się dzieje, może istnieje inna droga.

0

@Patryk27 Mam Delphi XE8.

Tak mi się wydawało, że to błąd projektowy, ale nie mam pomysłu jak go rozwiązać. Sytuacja wygląda tak: mam potworka, dwóch graczy i samonaprowadzający pocisk. Pierwszy gracz jest na drugim końcu mapy i strzela pociskiem w potworka. Zanim pocisk zdąży dolecieć potworek jest zabijany przez drugiego gracza. Cel pocisku przestał istnieć, więc wybucha on w miejscu do którego doleciał.

Obecnie robię to tak, że w momencie strzału przypisuje obiekt potworka do pocisku, żeby pocisk aktualizował pozycję celu. I tu pojawia się problem. Jeśli obiekt potworka zostanie zwolniony(przy zabiciu przez gracza drugiego) to referencja wskazuje na śmieci(zwolnioną pamięć).

2

Ach, klasyczny problem :)
Poczytaj o systemie zdarzeń w grach (event queue, są materiały w internecie).

1

I ja się dołączę, to jest błąd projektowy. Nie możesz tak robić i nie powinieneś do tego dopuszczać.
Poza tym, zawsze możesz przeciążyć metodę 'BeforeDestruction' obiektu, aby robić coś przed zwolnieniem - np. pozbyć się śmieci.
Możesz też zwalniać obiekt za pomocą FreeAndNil - ale to nie jest żadne rozwiązanie, tak naprawdę...
Poczytaj sobie informacje zawarte na tej stornie:
http://otapi.com/
Jest tam też odpowiedni kod, tylko brać zrozumieć i korzystać.

0

@Patryk27 dzięki za naprowadzenie. Już mniej więcej wiem jak to zrobić.
@wloochacz dzięki za linka. Właśnie FreeAndNil tutaj nie zadziała, bo po zwolnieniu obiektu referencje nie są zerowane.

0
Tajiri napisał(a):

@wloochacz dzięki za linka. Właśnie FreeAndNil tutaj nie zadziała, bo po zwolnieniu obiektu referencje nie są zerowane.

Słucham? A jak wg Ciebie działa FreeAndNil, bo wg mnie właśnie robi to czego oczekujesz - niszczy obiekt i przypisuje nil do zmiennej, która przechowywała jego referencję.

0

@wloochacz Tak, ale jak masz dwie referencje do jednego obiektu to jak na jednej dasz FreeAndNil to druga nie zostanie automatycznie wyzerowana tylko będzie odnosić się do zwolnionej pamięci.

0

Oczywiście, że tak będzie. I dlatego potrzebny jest Ci system powiadamiania o zdarzeniach, który możesz realizować na wiele rożnych sposobów. I w tym wątku padły co najmniej trzy możliwe rozwiązania...

1

Uważaj @Tajiri na obserwatory, bo jeśli w obiekcie A zarejestrujesz metodę obserwatora obiektu B, czyli coś takiego: A.Observers.Add(B.ObserverExecution) i zniszczysz obiekt B bez wyrejestrowania metody obserwatora, to będziesz miał podobne problemy....
Poważnie, zainteresuj się Event Engine, albo naprawdę ostrożnie podejdź do implementacji. A jeśli tego nie zrobisz, to wycieki pamięci będą Twoim najmniejszym zmartwieniem.

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