2009-06-24 3 views
7

patrzę na niektóre kodu (Delphi 7) W następstwie wyboru jest na szczycie każdego wywołania metody dla konkretnego obiektu:Dlaczego miałbyś sprawdzić Assigned (self) w metodach object?

if not Assigned(self) then 
    raise Exception.CreateRes(@sAbstractError); 

    { Real code for this method} 

myślę, że byłoby to przeszkadza mi próbuje wywołać metodę na zerowy wskaźnik obiektu. Ale dostanę wyjątek, gdy tylko spróbuję uzyskać dostęp do danych członków w takim przypadku, prawda?

Czy to jakiś standard, którego nigdy wcześniej nie widziałem? Przedmiot, o którym mowa, pochodzi z TPersistent.

Odpowiedz

8

Możesz wywołać metodę instancji na wskaźniku zerowym, chociaż nie jest to rzecz, którą chcesz robić celowo. Kiedy tak się dzieje, wykonanie trwa całkiem szczęśliwie, dopóki nie będzie musiało uzyskać dostępu do danych instancji, a następnie wszystko pójdzie dobrze.

W takim przypadku sprawdzenie wartości zerowej spowodowałoby ostrzeżenie u góry procedury, aby można było wykonać inne czynności, na przykład rejestrować ślad stosu. Lub możesz postawić punkt przerwania na linii podbicia, abyś mógł zanurkować i zobaczyć, co się dzieje.

To jest coś, co mógłbym zrobić, gdybym miał konkretny błąd, który próbowałem wyśledzić, gdzie użyto referencji zerowej.

Robiąc to regularnie uderza mnie jako zapach kodu.

4

Istnieją scenariusze naruszenia zasad dostępu, które mogą prowadzić do kodu działającego w pamięci, w którym wartość Self jest zerowa. Niektórzy programiści, zamiast rozwiązywać rzeczywisty problem, próbują ominąć, używają takich twierdzeń, aby zapobiegać wszelkiego rodzaju uszkodzeniom. Sprawdziłbym bardzo dobrze, czy ten wyjątek kiedykolwiek powstaje w czasie działania, jeśli tak - masz pod ręką buggy code.

Możesz przeczytać następujący artykuł na temat: When Self in Nil... You Know You are in Trouble.

Inna możliwość jest związana ze zdarzeniami, możesz przeczytać więcej tutaj, z dużą ilością przykładów takich testów i odpowiadającymi wyjaśnieniami: Multicast Events - Part 2.

+2

Nie powiedziałbym, że ten przykładowy kod w ogóle pomija prawdziwy problem. Przeciwnie, wyraźnie podkreśla problem. –

10

Jasny błąd narzekający na wskaźnik zerowy jest lepszy niż naruszenie zasad dostępu, które nie mówi, jak to się stało.

+1

+1 za złapanie wskaźnika zerowego zamiast naruszenia * możliwego * dostępu. –

+0

Więc mówisz, że kodujesz wszystkie swoje obiekty w ten sposób? –

+0

Bardzo trudno jest zerwać wskaźnik dereferencji. Nie masz tam pamięci. –

1

A ponadto zawsze istnieje możliwość, że kod nie ulegnie awarii podczas działania z zerowym Self. Przykład - jeśli nie ma dostępu do pól obiektu właściciela. W takim przypadku test ten wykryłby problem, który w innym przypadku byłby niewykryty.

Mimo to programowanie defensywne jest ekstremalne. Nigdy (OK, prawie nigdy - tylko wtedy, gdy poluję na wabbity ... errr ... zmiażdżenie robaków), rób to.

+0

Mimo że zrobiłem to - jest to kiepska forma użycia metody nieklasowanej, jak gdyby była to metoda klasowa. –

1

Wydaje się, że pierwotną intencją tej metody jest abstrakcyjna metoda.

3

Jest to okazja, która zdecydowanie powinna doprowadzić do awarii (tj. Wyjątek systemu operacyjnego, taki jak "odczyt z adresu 0x00000000"). Rzucanie wyjątku języka jest po prostu zbędne (i niewłaściwe użycie EAbstractError tutaj nie czyni go lepszym).

Sprawdzanie poprawnych parametrów wejściowych nie jest wykonalnym zadaniem w niebezpiecznym języku, ponieważ nigdy nie uzyskasz pewności, a zatem obsługa nieprawidłowych parametrów nigdy nie będzie spójna. (Dlaczego wyrzucasz wyjątek po przekazaniu wskaźnika zerowego, ale nie dla 0x00000001, który jest tak samo nieważny?). Aby uzyskać bardziej techniczną dyskusję na temat tego pytania, przeczytaj blog Larry'ego Ostermana o numerze: why not to check for valid pointers.

Należy zwrócić uwagę na jeden wyjątek: w Delphi metoda Free może być wywołana na wskaźniku zerowym, co oczywiście wymaga tego rodzaju sprawdzenia.